php_embed 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +2 -0
- data/Rakefile +12 -0
- data/ext/php_embed/extconf.rb +10 -0
- data/ext/php_embed/php.c +221 -0
- data/lib/php_embed/version.rb +3 -0
- data/lib/php_embed.rb +7 -0
- data/php_embed.gemspec +19 -0
- data/spec/php_spec.rb +89 -0
- metadata +59 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 do-aki
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/ext/php_embed/php.c
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <ruby.h>
|
3
|
+
#include <sapi/embed/php_embed.h>
|
4
|
+
|
5
|
+
static VALUE callback_output = Qnil;
|
6
|
+
static VALUE callback_error = Qnil;
|
7
|
+
|
8
|
+
static int php_ub_write(const char *str, unsigned int str_length TSRMLS_DC)
|
9
|
+
{
|
10
|
+
if (!NIL_P(callback_output)) {
|
11
|
+
VALUE args = rb_ary_new();
|
12
|
+
rb_ary_push(args, rb_str_new(str, str_length));
|
13
|
+
rb_proc_call(callback_output, args);
|
14
|
+
}
|
15
|
+
return str_length;
|
16
|
+
}
|
17
|
+
static void php_log_message(char *message)
|
18
|
+
{
|
19
|
+
if (!NIL_P(callback_error)) {
|
20
|
+
rb_proc_call(callback_error, rb_ary_new3(1, rb_str_new(message, strlen(message))));
|
21
|
+
}
|
22
|
+
}
|
23
|
+
static void php_sapi_error(int type, const char *fmt, ...)
|
24
|
+
{
|
25
|
+
va_list va;
|
26
|
+
va_start(va, fmt);
|
27
|
+
printf("php_sapi_error: ");
|
28
|
+
vprintf(fmt, va);
|
29
|
+
va_end(va);
|
30
|
+
}
|
31
|
+
|
32
|
+
VALUE zval_to_value(zval* val) {
|
33
|
+
VALUE r;
|
34
|
+
|
35
|
+
switch(Z_TYPE_P(val)) {
|
36
|
+
case IS_NULL:
|
37
|
+
return Qnil;
|
38
|
+
case IS_BOOL:
|
39
|
+
return (zval_is_true(val)) ? Qtrue : Qfalse;
|
40
|
+
case IS_LONG:
|
41
|
+
return INT2NUM(Z_LVAL_P(val));
|
42
|
+
case IS_DOUBLE:
|
43
|
+
return DBL2NUM(Z_DVAL_P(val));
|
44
|
+
case IS_ARRAY:
|
45
|
+
{
|
46
|
+
HashTable* ht = Z_ARRVAL_P(val);
|
47
|
+
HashPosition p;
|
48
|
+
int idx = 0;
|
49
|
+
zval** data;
|
50
|
+
|
51
|
+
r = rb_ary_new2(zend_hash_num_elements(ht));
|
52
|
+
|
53
|
+
zend_hash_internal_pointer_reset_ex(ht, &p);
|
54
|
+
while (zend_hash_get_current_data_ex(ht, (void **)&data, &p) == SUCCESS) {
|
55
|
+
VALUE t = zval_to_value(*data);
|
56
|
+
rb_ary_store(r, idx++, t);
|
57
|
+
zend_hash_move_forward_ex(ht, &p);
|
58
|
+
}
|
59
|
+
return r;
|
60
|
+
}
|
61
|
+
case IS_OBJECT:
|
62
|
+
case IS_STRING:
|
63
|
+
case IS_RESOURCE:
|
64
|
+
case IS_CONSTANT:
|
65
|
+
case IS_CONSTANT_ARRAY:
|
66
|
+
default:
|
67
|
+
convert_to_string(val);
|
68
|
+
return rb_str_new(Z_STRVAL_P(val), Z_STRLEN_P(val));
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
void value2php_arg(VALUE v, char* out_arg) {
|
73
|
+
switch (TYPE(v)) {
|
74
|
+
case T_FALSE:
|
75
|
+
strcat(out_arg, "false");
|
76
|
+
return;
|
77
|
+
case T_TRUE:
|
78
|
+
strcat(out_arg, "true");
|
79
|
+
return;
|
80
|
+
case T_UNDEF:
|
81
|
+
case T_NIL:
|
82
|
+
strcat(out_arg, "null");
|
83
|
+
return;
|
84
|
+
case T_FIXNUM:
|
85
|
+
{
|
86
|
+
VALUE t = rb_fix2str(v, 10);
|
87
|
+
strcat(out_arg, StringValuePtr(t));
|
88
|
+
}
|
89
|
+
return;
|
90
|
+
case T_BIGNUM:
|
91
|
+
{
|
92
|
+
VALUE t = rb_big2str(v, 10);
|
93
|
+
strcat(out_arg, StringValuePtr(t));
|
94
|
+
}
|
95
|
+
return;
|
96
|
+
case T_FLOAT:
|
97
|
+
{
|
98
|
+
VALUE t = rb_funcall(v, rb_intern("to_s"), 0);
|
99
|
+
strcat(out_arg, StringValuePtr(t));
|
100
|
+
}
|
101
|
+
return;
|
102
|
+
case T_ARRAY:
|
103
|
+
{
|
104
|
+
int i;
|
105
|
+
strcat(out_arg, "array(");
|
106
|
+
for(i=0;i<RARRAY_LEN(v);++i) {
|
107
|
+
value2php_arg(RARRAY_PTR(v)[i], out_arg);
|
108
|
+
if (i != RARRAY_LEN(v)-1) {
|
109
|
+
strcat(out_arg, ",");
|
110
|
+
}
|
111
|
+
}
|
112
|
+
strcat(out_arg, ")");
|
113
|
+
}
|
114
|
+
case T_HASH:
|
115
|
+
/* no implement */
|
116
|
+
return;
|
117
|
+
case T_STRING:
|
118
|
+
default:
|
119
|
+
strcat(out_arg, "'");
|
120
|
+
strcat(out_arg, StringValuePtr(v));
|
121
|
+
strcat(out_arg, "'");
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
int eval_php_code(char* code, VALUE* return_value) {
|
126
|
+
const char *argv[2] = {"ruby", NULL};
|
127
|
+
int err = 0;
|
128
|
+
zval **data;
|
129
|
+
zval retval;
|
130
|
+
|
131
|
+
PHP_EMBED_START_BLOCK(1, (char**)argv);
|
132
|
+
|
133
|
+
if (zend_eval_string(code, &retval, (char*)"" TSRMLS_CC) == FAILURE) {
|
134
|
+
err = 1;
|
135
|
+
}
|
136
|
+
|
137
|
+
PHP_EMBED_END_BLOCK();
|
138
|
+
|
139
|
+
*return_value = zval_to_value(&retval);
|
140
|
+
zval_dtor(&retval);
|
141
|
+
|
142
|
+
return err;
|
143
|
+
}
|
144
|
+
|
145
|
+
VALUE php_eval(VALUE self, VALUE code) {
|
146
|
+
VALUE retval;
|
147
|
+
if (eval_php_code(StringValuePtr(code), &retval)) {
|
148
|
+
rb_raise(rb_eRuntimeError, "invalid code");
|
149
|
+
}
|
150
|
+
|
151
|
+
return retval;
|
152
|
+
}
|
153
|
+
|
154
|
+
VALUE php_call(int argc, VALUE *argv, VALUE self) {
|
155
|
+
VALUE func, args, retval;
|
156
|
+
int i;
|
157
|
+
char arg_str[1024], call_str[2048];
|
158
|
+
zval* t = NULL;
|
159
|
+
|
160
|
+
rb_scan_args(argc, argv, "1*", &func, &args);
|
161
|
+
|
162
|
+
|
163
|
+
arg_str[0] = '\0';
|
164
|
+
for(i=0; i<argc-1; ++i) {
|
165
|
+
char arg[255] = "";
|
166
|
+
value2php_arg(RARRAY_PTR(args)[i], arg);
|
167
|
+
strcat(arg_str, arg);
|
168
|
+
|
169
|
+
if (i != argc-2) {
|
170
|
+
strcat(arg_str, ",");
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
sprintf(call_str, "%s(%s)", StringValuePtr(func), arg_str);
|
175
|
+
//printf("\n***%s***\n", call_str);
|
176
|
+
if (eval_php_code(call_str, &retval)) {
|
177
|
+
rb_raise(rb_eRuntimeError, "eval error");
|
178
|
+
}
|
179
|
+
|
180
|
+
return retval;
|
181
|
+
}
|
182
|
+
|
183
|
+
VALUE php_set_output_handler(VALUE self, VALUE callback) {
|
184
|
+
if (rb_obj_is_proc(callback)) {
|
185
|
+
callback_output = callback;
|
186
|
+
} else {
|
187
|
+
rb_raise(rb_eArgError, "callback must be proc");
|
188
|
+
}
|
189
|
+
|
190
|
+
return Qnil;
|
191
|
+
}
|
192
|
+
|
193
|
+
VALUE php_set_error_handler(VALUE self, VALUE callback) {
|
194
|
+
if (rb_obj_is_proc(callback)) {
|
195
|
+
callback_error = callback;
|
196
|
+
} else {
|
197
|
+
rb_raise(rb_eArgError, "callback must be proc");
|
198
|
+
}
|
199
|
+
|
200
|
+
return Qnil;
|
201
|
+
}
|
202
|
+
|
203
|
+
Init_php() {
|
204
|
+
|
205
|
+
VALUE cPhp;
|
206
|
+
cPhp = rb_define_module("PhpEmbed");
|
207
|
+
//rb_define_const(cPhp, "VERSION", rb_ary_new3(3, INT2FIX(0), INT2FIX(0), INT2FIX(1)));
|
208
|
+
|
209
|
+
rb_define_singleton_method(cPhp, "eval", php_eval, 1);
|
210
|
+
rb_define_singleton_method(cPhp, "call", php_call, -1);
|
211
|
+
rb_define_singleton_method(cPhp, "setOutputHandler", php_set_output_handler, 1);
|
212
|
+
rb_define_singleton_method(cPhp, "setErrorHandler", php_set_error_handler, 1);
|
213
|
+
|
214
|
+
php_embed_module.ub_write = php_ub_write;
|
215
|
+
php_embed_module.log_message = php_log_message;
|
216
|
+
php_embed_module.sapi_error = php_sapi_error;
|
217
|
+
|
218
|
+
}
|
219
|
+
|
220
|
+
|
221
|
+
|
data/lib/php_embed.rb
ADDED
data/php_embed.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/php_embed/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["do_aki"]
|
6
|
+
gem.email = ["do.hiroaki@gmail.com"]
|
7
|
+
gem.description = %q{execute PHP code in Ruby code}
|
8
|
+
gem.summary = %q{execute PHP code in Ruby code}
|
9
|
+
gem.homepage = %q{https://github.com/do-aki/php_embed}
|
10
|
+
|
11
|
+
gem.extensions = ['ext/php_embed/extconf.rb']
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "php_embed"
|
16
|
+
gem.require_paths = ['ext/php_embed/', 'ext/php_embed/']
|
17
|
+
gem.version = PhpEmbed::VERSION
|
18
|
+
|
19
|
+
end
|
data/spec/php_spec.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'php_embed'
|
3
|
+
|
4
|
+
describe 'PhpEmbed' do
|
5
|
+
|
6
|
+
describe 'eval' do
|
7
|
+
it 'return any types' do
|
8
|
+
PhpEmbed.eval('true').should be_true
|
9
|
+
PhpEmbed.eval('false').should be_false;
|
10
|
+
PhpEmbed.eval('null').should be_nil
|
11
|
+
PhpEmbed.eval('1').should == 1
|
12
|
+
PhpEmbed.eval('array()').should == []
|
13
|
+
PhpEmbed.eval('array(1)').should == [1]
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'raise error with invalid PhpEmbed code' do
|
17
|
+
proc {
|
18
|
+
PhpEmbed.eval("i n v a l i d")
|
19
|
+
}.should raise_error
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'call' do
|
24
|
+
it 'return phpversion' do
|
25
|
+
PhpEmbed.call("phpversion").should == "5.4.5"
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'bin2hex return hex string' do
|
29
|
+
PhpEmbed.call("bin2hex", "+").should == "2b"
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'intval return integer value' do
|
33
|
+
PhpEmbed.call("intval", "123a").should == 123
|
34
|
+
PhpEmbed.call("intval", 123).should == 123
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'floatval return float value' do
|
38
|
+
PhpEmbed.call("floatval", "-8.93").should == -8.93
|
39
|
+
PhpEmbed.call("floatval", -8.93).should == -8.93
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'call with integer' do
|
43
|
+
PhpEmbed.call("pow", 2, 8).should == 256
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'call with array' do
|
47
|
+
PhpEmbed.call("array_diff", [1,2,3,4,5], [3,4]).should == [1,2,5]
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raise error with invalid PhpEmbed code' do
|
51
|
+
proc {
|
52
|
+
PhpEmbed.call("i n v a l i d")
|
53
|
+
}.should raise_error
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'output' do
|
58
|
+
it 'handling output' do
|
59
|
+
capture = nil
|
60
|
+
PhpEmbed.setOutputHandler(Proc.new { |output|
|
61
|
+
capture = output
|
62
|
+
})
|
63
|
+
|
64
|
+
PhpEmbed.eval('print("hoge")')
|
65
|
+
capture.should == 'hoge'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'error' do
|
70
|
+
it 'handling error' do
|
71
|
+
capture = []
|
72
|
+
PhpEmbed.setErrorHandler(Proc.new { |error|
|
73
|
+
capture << error
|
74
|
+
})
|
75
|
+
|
76
|
+
PhpEmbed.eval('trigger_error("hoge")')
|
77
|
+
capture.should == [
|
78
|
+
"PHP Notice: hoge in on line 1",
|
79
|
+
"PHP Stack trace:",
|
80
|
+
"PHP 1. {main}() :0",
|
81
|
+
"PHP 2. trigger_error() :1"
|
82
|
+
]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: php_embed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- do_aki
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-29 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: execute PHP code in Ruby code
|
15
|
+
email:
|
16
|
+
- do.hiroaki@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions:
|
19
|
+
- ext/php_embed/extconf.rb
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- Gemfile
|
24
|
+
- LICENSE
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- ext/php_embed/extconf.rb
|
28
|
+
- ext/php_embed/php.c
|
29
|
+
- lib/php_embed.rb
|
30
|
+
- lib/php_embed/version.rb
|
31
|
+
- php_embed.gemspec
|
32
|
+
- spec/php_spec.rb
|
33
|
+
homepage: https://github.com/do-aki/php_embed
|
34
|
+
licenses: []
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- ext/php_embed/
|
39
|
+
- ext/php_embed/
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.8.23
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: execute PHP code in Ruby code
|
58
|
+
test_files:
|
59
|
+
- spec/php_spec.rb
|