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
data/.autotest
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'autotest/restart'
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.extra_files << "../some/external/dependency.rb"
|
7
|
+
#
|
8
|
+
# at.libs << ":../some/external"
|
9
|
+
#
|
10
|
+
# at.add_exception 'vendor'
|
11
|
+
#
|
12
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
13
|
+
# at.files_matching(/test_.*rb$/)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# %w(TestA TestB).each do |klass|
|
17
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
|
21
|
+
# Autotest.add_hook :run_command do |at|
|
22
|
+
# system "rake build"
|
23
|
+
# end
|
data/CHANGELOG.rdoc
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
.autotest
|
2
|
+
CHANGELOG.rdoc
|
3
|
+
Manifest.txt
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
bin/phrack
|
7
|
+
bin/phuby
|
8
|
+
bin/phuby_server
|
9
|
+
ext/phuby/extconf.rb
|
10
|
+
ext/phuby/phuby.c
|
11
|
+
ext/phuby/phuby.h
|
12
|
+
ext/phuby/phuby_array.c
|
13
|
+
ext/phuby/phuby_array.h
|
14
|
+
ext/phuby/phuby_conversions.c
|
15
|
+
ext/phuby/phuby_conversions.h
|
16
|
+
ext/phuby/phuby_runtime.c
|
17
|
+
ext/phuby/phuby_runtime.h
|
18
|
+
lib/phuby.rb
|
19
|
+
lib/phuby/array.rb
|
20
|
+
lib/phuby/events.rb
|
21
|
+
lib/phuby/php_handler.rb
|
22
|
+
lib/phuby/rails.rb
|
23
|
+
lib/phuby/runtime.rb
|
24
|
+
php.patch
|
25
|
+
test/assets/hello_world.php
|
26
|
+
test/assets/htdocs/index.php
|
27
|
+
test/helper.rb
|
28
|
+
test/test_array.rb
|
29
|
+
test/test_handlers.rb
|
30
|
+
test/test_header_sent.rb
|
31
|
+
test/test_nil.rb
|
32
|
+
test/test_object.rb
|
33
|
+
test/test_php_handler.rb
|
34
|
+
test/test_phuby.rb
|
35
|
+
test/test_runtime.rb
|
data/README.rdoc
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
= phuby
|
2
|
+
|
3
|
+
* http://github.com/tenderlove/phuby
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Phuby wraps PHP in a loving embrace. Exposes a PHP runtime in ruby
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
* many
|
12
|
+
|
13
|
+
== SYNOPSIS:
|
14
|
+
|
15
|
+
rt = Phuby::Runtime.new
|
16
|
+
rt.start
|
17
|
+
|
18
|
+
rt.eval('$hello = "world"')
|
19
|
+
assert_equal "world", rt['hello']
|
20
|
+
|
21
|
+
rt.stop
|
22
|
+
|
23
|
+
== REQUIREMENTS:
|
24
|
+
|
25
|
+
* php
|
26
|
+
|
27
|
+
== BUILD INSTRUCTIONS:
|
28
|
+
|
29
|
+
* Download php-5.3.0
|
30
|
+
|
31
|
+
The following instructions apply to OS X (probably not needed on linux):
|
32
|
+
|
33
|
+
DO NOT change the prefix... No, I don't know why yet.
|
34
|
+
|
35
|
+
=== Install iconv with macports
|
36
|
+
|
37
|
+
$ sudo port install iconv
|
38
|
+
|
39
|
+
=== Install MySQL with macports
|
40
|
+
|
41
|
+
$ sudo port install mysql5 mysql5-server
|
42
|
+
|
43
|
+
Set some symbolic links:
|
44
|
+
|
45
|
+
$ cd /opt/local
|
46
|
+
$ sudo ln -s mysql5/mysql include/mysql
|
47
|
+
$ sudo ln -s mysql5/mysql/libmysqlclient.15.dylib lib/libmysqlclient.dylib
|
48
|
+
|
49
|
+
=== Patch and configure php
|
50
|
+
|
51
|
+
If you're on OS X, apply php.patch to the downloaded php. Then configure
|
52
|
+
php with the proper flags. These paths are for OS X, but you should be able
|
53
|
+
to adjust them for linux:
|
54
|
+
|
55
|
+
$ patch -p0 < ../path/to/php.patch
|
56
|
+
|
57
|
+
$ ./configure --enable-debug \
|
58
|
+
--enable-embed \
|
59
|
+
--disable-cli \
|
60
|
+
--with-mysql=/opt/local \
|
61
|
+
--with-mysqli=/opt/local/lib/mysql5/bin/mysql_config \
|
62
|
+
--with-mysql-sock=/opt/local/var/run/mysql5/mysqld.sock \
|
63
|
+
--prefix=/usr/local
|
64
|
+
|
65
|
+
$ make && sudo make install
|
66
|
+
|
67
|
+
Then, either install the gem, or rake test
|
68
|
+
|
69
|
+
== INSTALL:
|
70
|
+
|
71
|
+
* No.
|
72
|
+
|
73
|
+
== LICENSE:
|
74
|
+
|
75
|
+
(The MIT License)
|
76
|
+
|
77
|
+
Copyright (c) Aaron Patterson and Ryan Davis of Seattle.rb
|
78
|
+
|
79
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
80
|
+
a copy of this software and associated documentation files (the
|
81
|
+
'Software'), to deal in the Software without restriction, including
|
82
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
83
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
84
|
+
permit persons to whom the Software is furnished to do so, subject to
|
85
|
+
the following conditions:
|
86
|
+
|
87
|
+
The above copyright notice and this permission notice shall be
|
88
|
+
included in all copies or substantial portions of the Software.
|
89
|
+
|
90
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
91
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
92
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
93
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
94
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
95
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
96
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
gem 'rake-compiler', '>= 0.4.1'
|
6
|
+
require "rake/extensiontask"
|
7
|
+
|
8
|
+
HOE = Hoe.spec 'phuby' do
|
9
|
+
developer('Aaron Patterson', 'aaronp@rubyforge.org')
|
10
|
+
self.readme_file = 'README.rdoc'
|
11
|
+
self.history_file = 'CHANGELOG.rdoc'
|
12
|
+
self.extra_rdoc_files = FileList['*.rdoc']
|
13
|
+
|
14
|
+
self.spec_extras = { :extensions => ["ext/phuby/extconf.rb"] }
|
15
|
+
end
|
16
|
+
|
17
|
+
RET = Rake::ExtensionTask.new("phuby", HOE.spec) do |ext|
|
18
|
+
ext.lib_dir = File.join('lib', 'phuby')
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::Task[:test].prerequisites << :compile
|
22
|
+
|
23
|
+
# vim: syntax=ruby
|
data/bin/phrack
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'phuby'
|
5
|
+
require 'rack'
|
6
|
+
|
7
|
+
##
|
8
|
+
# Rack::Phrack is a Rack handler that will evaulate and serve PHP files.
|
9
|
+
|
10
|
+
class Rack::Phrack < Rack::File
|
11
|
+
class Events < Struct.new(:code, :headers, :body)
|
12
|
+
def write string; body << string; end
|
13
|
+
def send_headers response_code; end
|
14
|
+
|
15
|
+
def header value, op
|
16
|
+
k, v = value.split(': ', 2)
|
17
|
+
self.code = 302 if k == 'Location'
|
18
|
+
headers[k] = [headers[k], Rack::Utils.unescape(v)].compact.join "\n"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def call env
|
23
|
+
events = Events.new 200, {}, ''
|
24
|
+
file = File.join @root, env['PATH_INFO']
|
25
|
+
file = File.join file, "index.php" if File.directory?(file)
|
26
|
+
|
27
|
+
return super unless file =~ /php$/
|
28
|
+
|
29
|
+
Dir.chdir(File.dirname(file)) do
|
30
|
+
Phuby::Runtime.php do |rt|
|
31
|
+
rt.eval "date_default_timezone_set('America/Los_Angeles');" # *shrug*
|
32
|
+
|
33
|
+
{ Rack::Utils.parse_query(env['QUERY_STRING']) => "_GET",
|
34
|
+
Rack::Utils.parse_query(env['rack.input'].read) => "_POST",
|
35
|
+
Rack::Utils.parse_query(env['HTTP_COOKIE'], ';') => "_COOKIE",
|
36
|
+
}.each do |from, to|
|
37
|
+
from.each { |k,v| rt[to][k] = v }
|
38
|
+
end
|
39
|
+
|
40
|
+
env.each { |k,v| rt['_SERVER'][k] = v || '' unless k =~ /^rack/ }
|
41
|
+
rt["_SERVER"]['REQUEST_URI'] = env['PATH_INFO']
|
42
|
+
|
43
|
+
rt.with_events(events) { open(file) { |f| rt.eval f } } # RUN!
|
44
|
+
end
|
45
|
+
end
|
46
|
+
events.to_a
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Rack::Handler::WEBrick.run(Rack::Phrack.new(ARGV[0] || Dir.pwd), :Port => 10101)
|
data/bin/phuby
ADDED
data/bin/phuby_server
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
|
2
|
+
|
3
|
+
# :stopdoc:
|
4
|
+
|
5
|
+
require 'mkmf'
|
6
|
+
|
7
|
+
config = Dir["/{usr,opt}/local/bin/php-config"]
|
8
|
+
prefix = `#{config} --prefix`.chomp
|
9
|
+
|
10
|
+
php_inc, php_lib = dir_config("php5", "#{prefix}/include", "#{prefix}/lib")
|
11
|
+
|
12
|
+
$INCFLAGS = "-I#{File.join(php_inc, "php").quote} #{$INCFLAGS}"
|
13
|
+
|
14
|
+
%w{ Zend TSRM main }.each do |dir|
|
15
|
+
$INCFLAGS = "-I#{File.join(php_inc, "php", dir).quote} #{$INCFLAGS}"
|
16
|
+
end
|
17
|
+
|
18
|
+
unless find_library("php5", "php_embed_init", php_lib)
|
19
|
+
abort "php is missing!"
|
20
|
+
end
|
21
|
+
|
22
|
+
create_makefile("phuby/phuby")
|
23
|
+
|
24
|
+
# :startdoc:
|
data/ext/phuby/phuby.c
ADDED
data/ext/phuby/phuby.h
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
#include <phuby.h>
|
2
|
+
|
3
|
+
VALUE cPhubyArray;
|
4
|
+
|
5
|
+
VALUE Data_Wrap_PhubyArray(VALUE rt, zval * value)
|
6
|
+
{
|
7
|
+
VALUE arry = Data_Wrap_Struct(cPhubyArray, 0, 0, value);
|
8
|
+
rb_iv_set(arry, "@runtime", rt);
|
9
|
+
return arry;
|
10
|
+
}
|
11
|
+
|
12
|
+
static VALUE length(VALUE self)
|
13
|
+
{
|
14
|
+
zval * array;
|
15
|
+
|
16
|
+
Data_Get_Struct(self, zval, array);
|
17
|
+
|
18
|
+
return INT2NUM(zend_hash_num_elements(Z_ARRVAL_P(array)));
|
19
|
+
}
|
20
|
+
|
21
|
+
static VALUE get(VALUE self, VALUE key)
|
22
|
+
{
|
23
|
+
zval * array;
|
24
|
+
zval **value;
|
25
|
+
|
26
|
+
Data_Get_Struct(self, zval, array);
|
27
|
+
|
28
|
+
switch(TYPE(key))
|
29
|
+
{
|
30
|
+
case T_FIXNUM:
|
31
|
+
if(SUCCESS == zend_hash_index_find(
|
32
|
+
Z_ARRVAL_P(array),
|
33
|
+
NUM2INT(key),
|
34
|
+
(void **)&value
|
35
|
+
)) {
|
36
|
+
return ZVAL2VALUE(rb_iv_get(self, "@runtime"), *value);
|
37
|
+
}
|
38
|
+
break;
|
39
|
+
default:
|
40
|
+
if(SUCCESS == zend_hash_find(
|
41
|
+
Z_ARRVAL_P(array),
|
42
|
+
StringValuePtr(key),
|
43
|
+
RSTRING_LEN(key) + 1, // Add one for the NULL byte
|
44
|
+
(void **)&value
|
45
|
+
)) {
|
46
|
+
return ZVAL2VALUE(rb_iv_get(self, "@runtime"), *value);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
return Qnil;
|
51
|
+
}
|
52
|
+
|
53
|
+
static VALUE set(VALUE self, VALUE key, VALUE value)
|
54
|
+
{
|
55
|
+
zval * array;
|
56
|
+
|
57
|
+
Data_Get_Struct(self, zval, array);
|
58
|
+
|
59
|
+
VALUE s_key = rb_funcall(key, rb_intern("to_s"), 0);
|
60
|
+
|
61
|
+
add_assoc_zval(array,
|
62
|
+
StringValuePtr(s_key),
|
63
|
+
VALUE2ZVAL(rb_iv_get(self, "@runtime"), value)
|
64
|
+
);
|
65
|
+
|
66
|
+
return self;
|
67
|
+
}
|
68
|
+
|
69
|
+
static VALUE key_eh(VALUE self, VALUE key)
|
70
|
+
{
|
71
|
+
zval * array;
|
72
|
+
zval **value;
|
73
|
+
|
74
|
+
Data_Get_Struct(self, zval, array);
|
75
|
+
|
76
|
+
if(zend_hash_exists(Z_ARRVAL_P(array),
|
77
|
+
StringValuePtr(key), RSTRING_LEN(key) + 1)) {
|
78
|
+
return Qtrue;
|
79
|
+
}
|
80
|
+
|
81
|
+
return Qfalse;
|
82
|
+
}
|
83
|
+
|
84
|
+
void init_phuby_array()
|
85
|
+
{
|
86
|
+
cPhubyArray = rb_define_class_under(mPhuby, "Array", rb_cObject);
|
87
|
+
|
88
|
+
rb_define_method(cPhubyArray, "length", length, 0);
|
89
|
+
rb_define_method(cPhubyArray, "get", get, 1);
|
90
|
+
rb_define_method(cPhubyArray, "set", set, 2);
|
91
|
+
rb_define_method(cPhubyArray, "key?", key_eh, 1);
|
92
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#include <phuby.h>
|
2
|
+
|
3
|
+
zval * Phuby_value_to_zval(VALUE rt, VALUE value)
|
4
|
+
{
|
5
|
+
zval *php_value;
|
6
|
+
|
7
|
+
MAKE_STD_ZVAL(php_value);
|
8
|
+
|
9
|
+
switch(TYPE(value))
|
10
|
+
{
|
11
|
+
case T_FIXNUM:
|
12
|
+
ZVAL_LONG(php_value, NUM2INT(value));
|
13
|
+
break;
|
14
|
+
|
15
|
+
case T_TRUE:
|
16
|
+
case T_FALSE:
|
17
|
+
ZVAL_BOOL(php_value, value == Qtrue ? 1 : 0);
|
18
|
+
break;
|
19
|
+
|
20
|
+
case T_FLOAT:
|
21
|
+
case T_BIGNUM:
|
22
|
+
ZVAL_DOUBLE(php_value, NUM2DBL(value));
|
23
|
+
break;
|
24
|
+
|
25
|
+
case T_STRING:
|
26
|
+
ZVAL_STRINGL(php_value, StringValuePtr(value), RSTRING_LEN(value), 1);
|
27
|
+
break;
|
28
|
+
case T_OBJECT:
|
29
|
+
case T_DATA:
|
30
|
+
{
|
31
|
+
object_init_ex(php_value, php_ruby_proxy);
|
32
|
+
VALUE map = rb_iv_get(rt, "@proxy_map");
|
33
|
+
rb_hash_aset(map, INT2NUM((int)php_value), value);
|
34
|
+
}
|
35
|
+
break;
|
36
|
+
case T_ARRAY:
|
37
|
+
{
|
38
|
+
array_init(php_value);
|
39
|
+
int i;
|
40
|
+
for(i = 0; i < RARRAY_LEN(value); i++) {
|
41
|
+
VALUE key = rb_funcall(INT2NUM(i), rb_intern("to_s"), 0);
|
42
|
+
VALUE thing = RARRAY_PTR(value)[i];
|
43
|
+
add_assoc_zval(php_value, StringValuePtr(key), Phuby_value_to_zval(rt, thing));
|
44
|
+
}
|
45
|
+
VALUE map = rb_iv_get(rt, "@proxy_map");
|
46
|
+
rb_hash_aset(map, INT2NUM((int)php_value), value);
|
47
|
+
}
|
48
|
+
break;
|
49
|
+
case T_NIL:
|
50
|
+
ZVAL_NULL(php_value);
|
51
|
+
break;
|
52
|
+
default:
|
53
|
+
rb_raise(rb_eRuntimeError, "Can't convert ruby object: %s %d", rb_class2name(CLASS_OF(value)), TYPE(value));
|
54
|
+
}
|
55
|
+
|
56
|
+
return php_value;
|
57
|
+
}
|
58
|
+
|
59
|
+
VALUE Phuby_zval_to_value(VALUE rt, zval * value)
|
60
|
+
{
|
61
|
+
switch(Z_TYPE_P(value)) {
|
62
|
+
case IS_NULL:
|
63
|
+
return Qnil;
|
64
|
+
break;
|
65
|
+
case IS_BOOL:
|
66
|
+
if(Z_BVAL_P(value))
|
67
|
+
return Qtrue;
|
68
|
+
else
|
69
|
+
return Qfalse;
|
70
|
+
break;
|
71
|
+
case IS_LONG:
|
72
|
+
return INT2NUM(Z_LVAL_P(value));
|
73
|
+
break;
|
74
|
+
case IS_DOUBLE:
|
75
|
+
return rb_float_new(Z_DVAL_P(value));
|
76
|
+
break;
|
77
|
+
case IS_STRING:
|
78
|
+
return rb_str_new(Z_STRVAL_P(value), Z_STRLEN_P(value));
|
79
|
+
break;
|
80
|
+
case IS_ARRAY:
|
81
|
+
return Data_Wrap_PhubyArray(rt, value);
|
82
|
+
break;
|
83
|
+
case IS_OBJECT:
|
84
|
+
{
|
85
|
+
VALUE map = rb_iv_get(rt, "@proxy_map");
|
86
|
+
return rb_hash_aref(map, INT2NUM((int)value));
|
87
|
+
}
|
88
|
+
default:
|
89
|
+
rb_raise(rb_eRuntimeError, "Whoa, I don't know how to convert that");
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|