phuby 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +23 -0
- data/CHANGELOG.rdoc +6 -0
- data/Manifest.txt +35 -0
- data/README.rdoc +96 -0
- data/Rakefile +23 -0
- data/bin/phrack +50 -0
- data/bin/phuby +3 -0
- data/bin/phuby_server +12 -0
- data/ext/phuby/extconf.rb +24 -0
- data/ext/phuby/phuby.c +11 -0
- data/ext/phuby/phuby.h +14 -0
- data/ext/phuby/phuby_array.c +92 -0
- data/ext/phuby/phuby_array.h +9 -0
- data/ext/phuby/phuby_conversions.c +92 -0
- data/ext/phuby/phuby_conversions.h +12 -0
- data/ext/phuby/phuby_runtime.c +243 -0
- data/ext/phuby/phuby_runtime.h +11 -0
- data/lib/phuby.rb +9 -0
- data/lib/phuby/array.rb +24 -0
- data/lib/phuby/events.rb +19 -0
- data/lib/phuby/php_handler.rb +96 -0
- data/lib/phuby/rails.rb +47 -0
- data/lib/phuby/runtime.rb +69 -0
- data/php.patch +145 -0
- data/test/assets/hello_world.php +6 -0
- data/test/assets/htdocs/index.php +22 -0
- data/test/helper.rb +19 -0
- data/test/test_array.rb +101 -0
- data/test/test_handlers.rb +49 -0
- data/test/test_header_sent.rb +25 -0
- data/test/test_nil.rb +10 -0
- data/test/test_object.rb +57 -0
- data/test/test_php_handler.rb +56 -0
- data/test/test_phuby.rb +90 -0
- data/test/test_runtime.rb +77 -0
- metadata +151 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Phuby
|
5
|
+
class Runtime
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
attr_accessor :events
|
9
|
+
|
10
|
+
def self.php &block
|
11
|
+
instance.php(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@events = Events.new
|
16
|
+
@mutex = Mutex.new
|
17
|
+
@proxy_map = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def started?
|
21
|
+
@mutex.locked?
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_events event
|
25
|
+
old = @events
|
26
|
+
@events = event
|
27
|
+
yield self
|
28
|
+
@events = old
|
29
|
+
end
|
30
|
+
|
31
|
+
def eval string_or_io, filename = nil
|
32
|
+
raise NotStartedError, "please start the runtime" unless @mutex.locked?
|
33
|
+
|
34
|
+
if string_or_io.respond_to? :read
|
35
|
+
native_eval_io string_or_io, filename || string_or_io.path
|
36
|
+
else
|
37
|
+
native_eval string_or_io, filename || __FILE__
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def php &block
|
42
|
+
start
|
43
|
+
block.call(self)
|
44
|
+
ensure
|
45
|
+
stop
|
46
|
+
end
|
47
|
+
|
48
|
+
def [] key
|
49
|
+
raise NotStartedError, "please start the runtime" unless @mutex.locked?
|
50
|
+
get key
|
51
|
+
end
|
52
|
+
|
53
|
+
def []= key, value
|
54
|
+
raise NotStartedError, "please start the runtime" unless @mutex.locked?
|
55
|
+
set key, value
|
56
|
+
end
|
57
|
+
|
58
|
+
class NotStartedError < RuntimeError; end
|
59
|
+
|
60
|
+
private
|
61
|
+
def call who, what, with
|
62
|
+
list = []
|
63
|
+
with.each do |obj|
|
64
|
+
list << obj
|
65
|
+
end
|
66
|
+
@proxy_map[who].send(what.to_sym, *list)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/php.patch
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
diff --git configure configure
|
2
|
+
index 365e20e..7d116ab 100755
|
3
|
+
--- configure
|
4
|
+
+++ configure
|
5
|
+
@@ -3480,7 +3480,7 @@ if test "$GCC" = "yes"; then
|
6
|
+
;;
|
7
|
+
esac
|
8
|
+
if test $GCC_MAJOR_VERSION -ge 4; then
|
9
|
+
- CFLAGS="$CFLAGS -fvisibility=hidden"
|
10
|
+
+ CFLAGS="$CFLAGS"
|
11
|
+
fi
|
12
|
+
fi
|
13
|
+
|
14
|
+
@@ -4406,12 +4406,12 @@ IFS="- /.
|
15
|
+
build_type=shared
|
16
|
+
;;
|
17
|
+
*darwin*)
|
18
|
+
- MH_BUNDLE_FLAGS="-dynamic -twolevel_namespace -bundle -bundle_loader $APXS_HTTPD"
|
19
|
+
+ MH_BUNDLE_FLAGS="-dylib -twolevel_namespace -bundle -bundle_loader $APXS_HTTPD"
|
20
|
+
|
21
|
+
PHP_VAR_SUBST="$PHP_VAR_SUBST MH_BUNDLE_FLAGS"
|
22
|
+
|
23
|
+
- SAPI_SHARED=libs/libphp5.so
|
24
|
+
- build_type=bundle
|
25
|
+
+ SAPI_SHARED=libs/libphp5.dylib
|
26
|
+
+ build_type=shared
|
27
|
+
;;
|
28
|
+
*)
|
29
|
+
build_type=shared
|
30
|
+
@@ -107680,7 +107680,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
|
31
|
+
if test "$GCC" = yes ; then
|
32
|
+
output_verbose_link_cmd='echo'
|
33
|
+
archive_cmds='$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring'
|
34
|
+
- module_cmds='$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags'
|
35
|
+
+ module_cmds='$CC $allow_undefined_flag -fPIC -o $lib -dynamiclib $libobjs $deplibs$compiler_flags'
|
36
|
+
# Don't fix this by using the ld -exported_symbols_list flag, it doesn't exist in older darwin lds
|
37
|
+
archive_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC -dynamiclib $allow_undefined_flag -o $lib $libobjs $deplibs $compiler_flags -install_name $rpath/$soname $verstring~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
|
38
|
+
module_expsym_cmds='sed -e "s,#.*,," -e "s,^[ ]*,," -e "s,^\(..*\),_&," < $export_symbols > $output_objdir/${libname}-symbols.expsym~$CC $allow_undefined_flag -o $lib -bundle $libobjs $deplibs$compiler_flags~nmedit -s $output_objdir/${libname}-symbols.expsym ${lib}'
|
39
|
+
diff --git configure.in configure.in
|
40
|
+
index dff131d..18c8e72 100644
|
41
|
+
--- configure.in
|
42
|
+
+++ configure.in
|
43
|
+
@@ -427,6 +427,7 @@ alloca.h \
|
44
|
+
arpa/inet.h \
|
45
|
+
arpa/nameser.h \
|
46
|
+
assert.h \
|
47
|
+
+crt_externs.h \
|
48
|
+
crypt.h \
|
49
|
+
fcntl.h \
|
50
|
+
grp.h \
|
51
|
+
diff --git ext/spl/spl_dllist.h ext/spl/spl_dllist.h
|
52
|
+
index 5b0998b..8360282 100644
|
53
|
+
--- ext/spl/spl_dllist.h
|
54
|
+
+++ ext/spl/spl_dllist.h
|
55
|
+
@@ -24,9 +24,9 @@
|
56
|
+
#include "php.h"
|
57
|
+
#include "php_spl.h"
|
58
|
+
|
59
|
+
-PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList;
|
60
|
+
-PHPAPI zend_class_entry *spl_ce_SplQueue;
|
61
|
+
-PHPAPI zend_class_entry *spl_ce_SplStack;
|
62
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplDoublyLinkedList;
|
63
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplQueue;
|
64
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplStack;
|
65
|
+
|
66
|
+
PHP_MINIT_FUNCTION(spl_dllist);
|
67
|
+
|
68
|
+
diff --git ext/spl/spl_fixedarray.h ext/spl/spl_fixedarray.h
|
69
|
+
index dd556be..f9a2d90 100644
|
70
|
+
--- ext/spl/spl_fixedarray.h
|
71
|
+
+++ ext/spl/spl_fixedarray.h
|
72
|
+
@@ -22,7 +22,7 @@
|
73
|
+
#ifndef SPL_FIXEDARRAY_H
|
74
|
+
#define SPL_FIXEDARRAY_H
|
75
|
+
|
76
|
+
-PHPAPI zend_class_entry *spl_ce_SplFixedArray;
|
77
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplFixedArray;
|
78
|
+
|
79
|
+
PHP_MINIT_FUNCTION(spl_fixedarray);
|
80
|
+
|
81
|
+
diff --git ext/spl/spl_heap.h ext/spl/spl_heap.h
|
82
|
+
index 56c82b5..1d29e57 100644
|
83
|
+
--- ext/spl/spl_heap.h
|
84
|
+
+++ ext/spl/spl_heap.h
|
85
|
+
@@ -24,11 +24,11 @@
|
86
|
+
#include "php.h"
|
87
|
+
#include "php_spl.h"
|
88
|
+
|
89
|
+
-PHPAPI zend_class_entry *spl_ce_SplHeap;
|
90
|
+
-PHPAPI zend_class_entry *spl_ce_SplMinHeap;
|
91
|
+
-PHPAPI zend_class_entry *spl_ce_SplMaxHeap;
|
92
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplHeap;
|
93
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplMinHeap;
|
94
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplMaxHeap;
|
95
|
+
|
96
|
+
-PHPAPI zend_class_entry *spl_ce_SplPriorityQueue;
|
97
|
+
+extern PHPAPI zend_class_entry *spl_ce_SplPriorityQueue;
|
98
|
+
|
99
|
+
PHP_MINIT_FUNCTION(spl_heap);
|
100
|
+
|
101
|
+
diff --git main/php.h main/php.h
|
102
|
+
index 58f4142..035d502 100644
|
103
|
+
--- main/php.h
|
104
|
+
+++ main/php.h
|
105
|
+
@@ -263,7 +263,13 @@ END_EXTERN_C()
|
106
|
+
#if !defined(PHP_WIN32)
|
107
|
+
#define PHP_SLEEP_NON_VOID
|
108
|
+
#define php_sleep sleep
|
109
|
+
+
|
110
|
+
+#if HAVE_CRT_EXTERNS_H
|
111
|
+
+#include <crt_externs.h>
|
112
|
+
+#define environ (*_NSGetEnviron())
|
113
|
+
+#else
|
114
|
+
extern char **environ;
|
115
|
+
+#endif
|
116
|
+
#endif /* !defined(PHP_WIN32) */
|
117
|
+
|
118
|
+
#ifdef PHP_PWRITE_64
|
119
|
+
diff --git main/php_getopt.h main/php_getopt.h
|
120
|
+
index 024ea5c..62f04d6 100644
|
121
|
+
--- main/php_getopt.h
|
122
|
+
+++ main/php_getopt.h
|
123
|
+
@@ -41,7 +41,7 @@ typedef struct _opt_struct {
|
124
|
+
|
125
|
+
BEGIN_EXTERN_C()
|
126
|
+
/* holds the index of the latest fetched element from the opts array */
|
127
|
+
-PHPAPI int php_optidx;
|
128
|
+
+extern PHPAPI int php_optidx;
|
129
|
+
PHPAPI int php_getopt(int argc, char* const *argv, const opt_struct opts[], char **optarg, int *optind, int show_err, int arg_start);
|
130
|
+
END_EXTERN_C()
|
131
|
+
|
132
|
+
diff --git sapi/cli/config.m4 sapi/cli/config.m4
|
133
|
+
index e804357..300b898 100644
|
134
|
+
--- sapi/cli/config.m4
|
135
|
+
+++ sapi/cli/config.m4
|
136
|
+
@@ -20,9 +20,6 @@ if test "$PHP_CLI" != "no"; then
|
137
|
+
BUILD_CLI="echo '\#! .' > php.sym && echo >>php.sym && nm -BCpg \`echo \$(PHP_GLOBAL_OBJS) \$(PHP_CLI_OBJS) | sed 's/\([A-Za-z0-9_]*\)\.lo/\1.o/g'\` | \$(AWK) '{ if (((\$\$2 == \"T\") || (\$\$2 == \"D\") || (\$\$2 == \"B\")) && (substr(\$\$3,1,1) != \".\")) { print \$\$3 } }' | sort -u >> php.sym && \$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) -Wl,-brtl -Wl,-bE:php.sym \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_CLI_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CLI_PATH)"
|
138
|
+
fi
|
139
|
+
;;
|
140
|
+
- *darwin*)
|
141
|
+
- BUILD_CLI="\$(CC) \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(NATIVE_RPATHS) \$(PHP_GLOBAL_OBJS:.lo=.o) \$(PHP_CLI_OBJS:.lo=.o) \$(PHP_FRAMEWORKS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_CLI_PATH)"
|
142
|
+
- ;;
|
143
|
+
*netware*)
|
144
|
+
BUILD_CLI="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \$(PHP_CLI_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -Lnetware -lphp5lib -o \$(SAPI_CLI_PATH)"
|
145
|
+
;;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title>
|
4
|
+
Hello
|
5
|
+
</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1>Get Params</h1>
|
9
|
+
<table id="get">
|
10
|
+
<?php
|
11
|
+
foreach($_GET as $key => $val) {
|
12
|
+
?>
|
13
|
+
<tr>
|
14
|
+
<td><?php echo $key; ?></td>
|
15
|
+
<td><?php echo $val; ?></td>
|
16
|
+
</tr>
|
17
|
+
<?php
|
18
|
+
}
|
19
|
+
?>
|
20
|
+
</table>
|
21
|
+
</body>
|
22
|
+
</html>
|
data/test/helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#Process.setrlimit(Process::RLIMIT_CORE, Process::RLIM_INFINITY) unless RUBY_PLATFORM =~ /(java|mswin|mingw)/i
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'phuby'
|
5
|
+
|
6
|
+
module Phuby
|
7
|
+
class TestCase < Test::Unit::TestCase
|
8
|
+
ASSETS_DIR = File.join(File.dirname(__FILE__), 'assets')
|
9
|
+
HTDOCS_DIR = File.join(File.dirname(__FILE__), 'assets', 'htdocs')
|
10
|
+
|
11
|
+
unless RUBY_VERSION >= '1.9'
|
12
|
+
undef :default_test
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup
|
16
|
+
warn "#{name}" if ENV['TESTOPTS'] == '-v'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/test/test_array.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestArray < Phuby::TestCase
|
4
|
+
def test_move_to_runtime
|
5
|
+
Phuby::Runtime.php do |rt|
|
6
|
+
rt['foo'] = [1,2,3]
|
7
|
+
assert_equal 1, rt['foo'][0]
|
8
|
+
assert_equal 2, rt['foo'][1]
|
9
|
+
assert_equal 3, rt['foo'][2]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_array_length
|
14
|
+
Phuby::Runtime.php do |rt|
|
15
|
+
rt.eval('$get_length = count($_GET);')
|
16
|
+
assert_equal rt['get_length'], rt['_GET'].length
|
17
|
+
|
18
|
+
10.times { |i|
|
19
|
+
rt.eval("$_GET['foo#{i}'] = 'bar'; $get_length = count($_GET);")
|
20
|
+
assert_equal rt['get_length'], rt['_GET'].length
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_index_numeric_get
|
26
|
+
Phuby::Runtime.php do |rt|
|
27
|
+
rt.eval('$foo = array(1,2,3,4,5);')
|
28
|
+
list = []
|
29
|
+
assert_equal 1, rt['foo'][0]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_index_numeric_set
|
34
|
+
Phuby::Runtime.php do |rt|
|
35
|
+
rt.eval('$foo = array(1,2,3,4,5);')
|
36
|
+
|
37
|
+
rt['foo'][0] = "hello"
|
38
|
+
|
39
|
+
rt.eval('$bar = $foo[0];')
|
40
|
+
|
41
|
+
assert_equal 'hello', rt['bar']
|
42
|
+
assert_equal 'hello', rt['foo'][0]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_each
|
47
|
+
Phuby::Runtime.php do |rt|
|
48
|
+
rt.eval('$foo = array(1,2,3,4,5);')
|
49
|
+
|
50
|
+
array = rt['foo']
|
51
|
+
|
52
|
+
other = []
|
53
|
+
array.each do |thing|
|
54
|
+
other << thing
|
55
|
+
end
|
56
|
+
assert_equal [1,2,3,4,5], other
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_to_a
|
61
|
+
Phuby::Runtime.php do |rt|
|
62
|
+
rt.eval('$foo = array(1,2,3,4,5);')
|
63
|
+
|
64
|
+
array = rt['foo']
|
65
|
+
|
66
|
+
assert_equal [1,2,3,4,5], array.to_a
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_get
|
71
|
+
Phuby::Runtime.php do |rt|
|
72
|
+
rt.eval('$_GET["foo"] = "bar";')
|
73
|
+
#rt.eval('var_dump($_GET);')
|
74
|
+
|
75
|
+
assert_equal 'bar', rt['_GET']['foo']
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_set
|
80
|
+
Phuby::Runtime.php do |rt|
|
81
|
+
rt['_GET']['foo'] = "bar"
|
82
|
+
rt.eval('$foo = $_GET["foo"];')
|
83
|
+
#rt.eval('var_dump($_GET);')
|
84
|
+
|
85
|
+
assert_equal 'bar', rt['foo']
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_get_non_existent
|
90
|
+
Phuby::Runtime.php do |rt|
|
91
|
+
assert_nil rt['_GET']['foo']
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_key?
|
96
|
+
Phuby::Runtime.php do |rt|
|
97
|
+
rt.eval('$_GET["foo"] = "bar";')
|
98
|
+
assert rt['_GET'].key? 'foo'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestHeaderHandler < Phuby::TestCase
|
4
|
+
def setup
|
5
|
+
super
|
6
|
+
@rt = Phuby::Runtime.instance
|
7
|
+
@rt.start
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
super
|
12
|
+
@rt.stop
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_capture_output
|
16
|
+
quiet = Class.new(Phuby::Events) {
|
17
|
+
attr_accessor :written
|
18
|
+
|
19
|
+
def write string
|
20
|
+
@written ||= []
|
21
|
+
@written << string
|
22
|
+
end
|
23
|
+
}.new
|
24
|
+
|
25
|
+
@rt.with_events(quiet) do |rt|
|
26
|
+
rt.eval 'echo "hello world";'
|
27
|
+
end
|
28
|
+
|
29
|
+
assert_equal ['hello world'], quiet.written
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_header_handler
|
33
|
+
header = Class.new(Phuby::Events) {
|
34
|
+
attr_accessor :headers
|
35
|
+
|
36
|
+
def header header, op
|
37
|
+
@headers ||= []
|
38
|
+
@headers << [header, op]
|
39
|
+
end
|
40
|
+
}.new
|
41
|
+
|
42
|
+
@rt.with_events(header) do |rt|
|
43
|
+
rt.eval 'setcookie("name", "Aaron", time()+3600);'
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_equal 1, header.headers.length
|
47
|
+
assert_equal :store, header.headers.first.last
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestHeaderSent < Phuby::TestCase
|
4
|
+
def test_headers_sent
|
5
|
+
header = Class.new(Phuby::Events) {
|
6
|
+
attr_accessor :response_code
|
7
|
+
|
8
|
+
def send_headers response_code
|
9
|
+
@response_code = response_code
|
10
|
+
end
|
11
|
+
}.new
|
12
|
+
|
13
|
+
@rt = Phuby::Runtime.instance
|
14
|
+
|
15
|
+
@rt.start
|
16
|
+
|
17
|
+
@rt.events = header
|
18
|
+
|
19
|
+
@rt.eval 'header("foo: bar", true, 500);'
|
20
|
+
|
21
|
+
@rt.stop
|
22
|
+
|
23
|
+
assert_equal 500, header.response_code
|
24
|
+
end
|
25
|
+
end
|