phuby 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|