2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2005-2011 Froenchenko Leonid ( lfroen@gmail.com / http://www.amule.org )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include <string> // Do_not_auto_remove (g++-4.0.1)
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
36 #ifdef PHP_STANDALONE_EN
42 # include "WebServer.h"
43 # include <ec/cpp/ECSpecialTags.h>
44 # include <wx/regex.h>
45 # include <wx/datetime.h>
48 #include "php_syntree.h"
49 #include "php_core_lib.h"
57 * Built-in php functions. Those are both library and core internals.
59 * I'm not going event to get near to what Zend provide, but
60 * at least base things must be here
64 * Print info about variable: php var_dump()
66 void php_var_dump(PHP_VALUE_NODE
*node
, int ident
, int ref
)
68 for(int i
= 0; i
< ident
;i
++) {
71 if ( ref
) printf("&");
73 case PHP_VAL_BOOL
: printf("bool(%s)\n", node
->int_val
? "true" : "false"); break;
74 case PHP_VAL_INT
: printf("int(%"PRIu64
")\n", node
->int_val
); break;
75 case PHP_VAL_FLOAT
: printf("float(%f)\n", node
->float_val
); break;
76 case PHP_VAL_STRING
: printf("string(%d) \"%s\"\n", (int)strlen(node
->str_val
), node
->str_val
); break;
77 case PHP_VAL_OBJECT
: printf("Object(%s)\n", node
->obj_val
.class_name
); break;
79 int arr_size
= array_get_size(node
);
80 printf("array(%d) {\n", arr_size
);
81 for(int i
= 0; i
< arr_size
;i
++) {
82 const std::string
&curr_key
= array_get_ith_key(node
, i
);
83 PHP_VAR_NODE
*curr_val
= array_get_by_str_key(node
, curr_key
);
84 printf("\t[%s]=>\n", curr_key
.c_str());
85 php_var_dump(&curr_val
->value
, ident
+1, curr_val
->ref_count
> 1);
87 for(int i
= 0; i
< ident
;i
++) {
93 case PHP_VAL_NONE
: printf("NULL\n"); break;
94 case PHP_VAL_VAR_NODE
:
95 case PHP_VAL_INT_DATA
: assert(0); break;
99 void php_native_var_dump(PHP_VALUE_NODE
*)
101 PHP_SCOPE_ITEM
*si
= get_scope_item(g_current_scope
, "__param_0");
103 assert((si
->type
== PHP_SCOPE_VAR
)||(si
->type
== PHP_SCOPE_PARAM
));
104 php_var_dump(&si
->var
->value
, 0, 0);
106 php_report_error(PHP_ERROR
, "Invalid or missing argument");
112 * Sorting stl-way requires operator ">"
117 SortElem(PHP_VAR_NODE
*p
) { obj
= p
; }
120 static PHP_SYN_FUNC_DECL_NODE
*callback
;
122 friend bool operator<(const SortElem
&o1
, const SortElem
&o2
);
125 PHP_SYN_FUNC_DECL_NODE
*SortElem::callback
= 0;
127 bool operator<(const SortElem
&o1
, const SortElem
&o2
)
129 PHP_VALUE_NODE result
;
131 value_value_assign(&SortElem::callback
->params
[0].si_var
->var
->value
, &o1
.obj
->value
);
132 value_value_assign(&SortElem::callback
->params
[1].si_var
->var
->value
, &o2
.obj
->value
);
134 switch_push_scope_table((PHP_SCOPE_TABLE_TYPE
*)SortElem::callback
->scope
);
137 // params passed by-value, all & notations ignored
139 result
.type
= PHP_VAL_NONE
;
140 php_execute(SortElem::callback
->code
, &result
);
141 cast_value_dnum(&result
);
143 // restore stack, free arg list
145 switch_pop_scope_table(0);
147 value_value_free(&SortElem::callback
->params
[0].si_var
->var
->value
);
148 value_value_free(&SortElem::callback
->params
[1].si_var
->var
->value
);
150 return result
.int_val
!= 0;
153 void php_native_usort(PHP_VALUE_NODE
*)
155 PHP_SCOPE_ITEM
*si
= get_scope_item(g_current_scope
, "__param_0");
156 if ( !si
|| (si
->var
->value
.type
!= PHP_VAL_ARRAY
)) {
157 php_report_error(PHP_ERROR
, "Invalid or missing argument (array)");
160 PHP_VAR_NODE
*array
= si
->var
;
161 si
= get_scope_item(g_current_scope
, "__param_1");
162 if ( !si
|| (si
->var
->value
.type
!= PHP_VAL_STRING
)) {
163 php_report_error(PHP_ERROR
, "Invalid or missing argument (func name)");
166 char *cmp_func_name
= si
->var
->value
.str_val
;
167 si
= get_scope_item(g_global_scope
, cmp_func_name
);
168 if ( !si
|| (si
->type
!= PHP_SCOPE_FUNC
)) {
169 php_report_error(PHP_ERROR
, "Compare function [%s] not found", cmp_func_name
);
172 PHP_SYN_FUNC_DECL_NODE
*func_decl
= si
->func
->func_decl
;
175 // usort invalidates keys, and sorts values
177 PHP_ARRAY_TYPE
*arr_obj
= (PHP_ARRAY_TYPE
*)array
->value
.ptr_val
;
179 // create vector of values
181 if ( arr_obj
->array
.size() == 0 ) {
182 php_report_error(PHP_WARNING
, "Sorting array of size 0");
186 std::list
<SortElem
> sort_list
;
187 for(PHP_ARRAY_ITER_TYPE i
= arr_obj
->array
.begin(); i
!= arr_obj
->array
.end(); i
++) {
188 sort_list
.push_back(SortElem(i
->second
));
190 SortElem::callback
= func_decl
;
193 arr_obj
->array
.clear();
194 arr_obj
->sorted_keys
.clear();
195 unsigned int key
= 0;
196 for(std::list
<SortElem
>::iterator i
= sort_list
.begin(); i
!= sort_list
.end(); i
++) {
197 array_add_to_int_key(&array
->value
, key
++, i
->obj
);
206 void php_native_strlen(PHP_VALUE_NODE
*result
)
208 PHP_SCOPE_ITEM
*si
= get_scope_item(g_current_scope
, "__param_0");
210 PHP_VALUE_NODE
*param
= &si
->var
->value
;
211 cast_value_str(param
);
213 cast_value_dnum(result
);
214 result
->int_val
= strlen(param
->str_val
);
217 php_report_error(PHP_ERROR
, "Invalid or missing argument");
221 void php_native_count(PHP_VALUE_NODE
*result
)
223 PHP_SCOPE_ITEM
*si
= get_scope_item(g_current_scope
, "__param_0");
225 PHP_VALUE_NODE
*param
= &si
->var
->value
;
227 cast_value_dnum(result
);
228 if ( (si
->var
->value
.type
== PHP_VAL_NONE
) || (si
->var
->value
.type
!= PHP_VAL_ARRAY
) ) {
231 result
->int_val
= array_get_size(param
);
235 php_report_error(PHP_ERROR
, "Invalid or missing argument");
239 void php_native_isset(PHP_VALUE_NODE
*result
)
241 PHP_SCOPE_ITEM
*si
= get_scope_item(g_current_scope
, "__param_0");
243 PHP_VALUE_NODE
*param
= &si
->var
->value
;
244 cast_value_str(param
);
246 cast_value_bool(result
);
247 result
->int_val
= (si
->var
->value
.type
== PHP_VAL_NONE
) ? 0 : 1;
250 php_report_error(PHP_ERROR
, "Invalid or missing argument");
254 void php_native_substr(PHP_VALUE_NODE
* /*result*/)
256 PHP_SCOPE_ITEM
*si_str
= get_scope_item(g_current_scope
, "__param_0");
257 PHP_VALUE_NODE
*str
= &si_str
->var
->value
;
261 php_report_error(PHP_ERROR
, "Invalid or missing argument 'str' for 'substr'");
264 PHP_SCOPE_ITEM
*si_start
= get_scope_item(g_current_scope
, "__param_1");
265 PHP_VALUE_NODE
*start
= &si_start
->var
->value
;
267 cast_value_dnum(start
);
269 php_report_error(PHP_ERROR
, "Invalid or missing argument 'start' for 'substr'");
273 PHP_SCOPE_ITEM
*si_end
= get_scope_item(g_current_scope
, "__param_2");
274 PHP_VALUE_NODE end
= { PHP_VAL_INT
, { 0 } };
276 end
= si_end
->var
->value
;
278 cast_value_dnum(&end
);
284 void php_native_split(PHP_VALUE_NODE
*result
)
287 cast_value_array(result
);
291 PHP_VALUE_NODE
*pattern
, *string_to_split
, *split_limit
;
292 PHP_SCOPE_ITEM
*si
= get_scope_item(g_current_scope
, "__param_0");
294 pattern
= &si
->var
->value
;
295 cast_value_str(pattern
);
297 php_report_error(PHP_ERROR
, "Invalid or missing argument: pattern");
300 si
= get_scope_item(g_current_scope
, "__param_1");
302 string_to_split
= &si
->var
->value
;
303 cast_value_str(string_to_split
);
305 php_report_error(PHP_ERROR
, "Invalid or missing argument: string");
308 si
= get_scope_item(g_current_scope
, "__param_2");
310 split_limit
= &si
->var
->value
;
311 cast_value_dnum(split_limit
);
313 php_report_error(PHP_ERROR
, "Invalid or missing argument: string");
316 #ifdef PHP_STANDALONE_EN
318 char error_buff
[256];
319 int reg_result
= regcomp(&preg
, pattern
->str_val
, REG_EXTENDED
);
321 regerror(reg_result
, &preg
, error_buff
, sizeof(error_buff
));
322 php_report_error(PHP_ERROR
, "Failed in regcomp: %s", error_buff
);
325 if (!preg
.Compile(wxString(char2unicode(pattern
->str_val
)), wxRE_EXTENDED
)) {
326 php_report_error(PHP_ERROR
, "Failed in Compile of: %s", pattern
->str_val
);
331 #ifdef PHP_STANDALONE_EN
332 size_t nmatch
= strlen(string_to_split
->str_val
);
333 regmatch_t
*pmatch
= new regmatch_t
[nmatch
];
335 char *str_2_match
= string_to_split
->str_val
;
336 char *tmp_buff
= new char[strlen(string_to_split
->str_val
)+1];
339 // printf("matching: %s\n", str_2_match);
340 #ifdef PHP_STANDALONE_EN
341 reg_result
= regexec(&preg
, str_2_match
, nmatch
, pmatch
, 0);
344 if (!preg
.Matches(wxString(char2unicode(str_2_match
)))) {
349 #ifndef PHP_STANDALONE_EN
350 // get matching position
352 if (!preg
.GetMatch(&start
, &len
)) {
353 break; // shouldn't happen
357 * I will use only first match, since I don't see any sense to have more
358 * then 1 match in split() call
360 #ifdef PHP_STANDALONE_EN
361 for(int i
= 0; i
< pmatch
[0].rm_so
; i
++) {
363 for(size_t i
= 0; i
< start
; i
++) {
365 tmp_buff
[i
] = str_2_match
[i
];
367 #ifdef PHP_STANDALONE_EN
368 tmp_buff
[pmatch
[0].rm_so
] = 0;
372 // printf("Match added [%s]\n", tmp_buff);
374 PHP_VAR_NODE
*match_val
= array_push_back(result
);
375 match_val
->value
.type
= PHP_VAL_STRING
;
376 match_val
->value
.str_val
= strdup(tmp_buff
);
378 #ifdef PHP_STANDALONE_EN
379 str_2_match
+= pmatch
[0].rm_eo
;
381 str_2_match
+= start
+ len
;
385 PHP_VAR_NODE
*match_val
= array_push_back(result
);
386 match_val
->value
.type
= PHP_VAL_STRING
;
387 match_val
->value
.str_val
= strdup(str_2_match
);
390 #ifdef PHP_STANDALONE_EN
398 void php_native_gettext(PHP_VALUE_NODE
*result
)
400 PHP_SCOPE_ITEM
*si_str
= get_scope_item(g_current_scope
, "__param_0");
401 PHP_VALUE_NODE
*str
= &si_str
->var
->value
;
405 php_report_error(PHP_ERROR
, "Invalid or missing argument 'msgid' for 'gettext'");
409 cast_value_dnum(result
);
410 result
->type
= PHP_VAL_STRING
;
411 result
->str_val
= strdup(gettext(str
->str_val
));
415 void php_native_gettext_noop(PHP_VALUE_NODE
*result
)
417 PHP_SCOPE_ITEM
*si_str
= get_scope_item(g_current_scope
, "__param_0");
418 PHP_VALUE_NODE
*str
= &si_str
->var
->value
;
422 php_report_error(PHP_ERROR
, "Invalid or missing argument 'msgid' for 'gettext_noop'");
426 cast_value_dnum(result
);
427 result
->type
= PHP_VAL_STRING
;
428 result
->str_val
= strdup(str
->str_val
);
432 void php_native_ngettext(PHP_VALUE_NODE
*result
)
434 PHP_SCOPE_ITEM
*si_msgid
= get_scope_item(g_current_scope
, "__param_0");
435 PHP_VALUE_NODE
*msgid
= &si_msgid
->var
->value
;
437 cast_value_str(msgid
);
439 php_report_error(PHP_ERROR
, "Invalid or missing argument 'msgid' for 'ngettext'");
442 PHP_SCOPE_ITEM
*si_msgid_plural
= get_scope_item(g_current_scope
, "__param_1");
443 PHP_VALUE_NODE
*msgid_plural
= &si_msgid_plural
->var
->value
;
444 if ( si_msgid_plural
) {
445 cast_value_str(msgid_plural
);
447 php_report_error(PHP_ERROR
, "Invalid or missing argument 'msgid_plural' for 'ngettext'");
450 PHP_SCOPE_ITEM
*si_count
= get_scope_item(g_current_scope
, "__param_2");
451 PHP_VALUE_NODE
*count
= &si_count
->var
->value
;
453 cast_value_dnum(count
);
455 php_report_error(PHP_ERROR
, "Invalid or missing argument 'count' for 'ngettext'");
459 cast_value_dnum(result
);
460 result
->type
= PHP_VAL_STRING
;
461 result
->str_val
= strdup(ngettext(msgid
->str_val
, msgid_plural
->str_val
, count
->int_val
));
466 PHP_BLTIN_FUNC_DEF core_lib_funcs
[] = {
474 1, php_native_strlen
,
497 1, php_native_gettext
,
501 1, php_native_gettext
,
505 1, php_native_gettext_noop
,
509 3, php_native_ngettext
,
515 void php_init_core_lib()
517 // load function definitions
518 PHP_BLTIN_FUNC_DEF
*curr_def
= core_lib_funcs
;
519 while ( curr_def
->name
) {
520 php_add_native_func(curr_def
);
526 // lexer has no include file
529 void php_set_input_buffer(char *buf
, int len
);
531 CPhPLibContext::CPhPLibContext(CWebServerBase
*server
, const char *file
)
533 g_curr_context
= this;
538 phpin
= fopen(file
, "r");
545 m_syn_tree_top
= g_syn_tree_top
;
546 m_global_scope
= g_global_scope
;
549 CPhPLibContext::CPhPLibContext(CWebServerBase
*server
, char *php_buf
, int len
)
551 g_curr_context
= this;
557 m_global_scope
= g_global_scope
;
559 php_set_input_buffer(php_buf
, len
);
562 m_syn_tree_top
= g_syn_tree_top
;
565 CPhPLibContext::~CPhPLibContext()
571 void CPhPLibContext::SetContext()
573 g_syn_tree_top
= m_syn_tree_top
;
574 g_global_scope
= m_global_scope
;
577 void CPhPLibContext::Execute(CWriteStrBuffer
*buf
)
579 m_curr_str_buffer
= buf
;
582 php_execute(g_syn_tree_top
, &val
);
585 CPhPLibContext
*CPhPLibContext::g_curr_context
= 0;
588 * For simplicity and performance sake, this function can
589 * only handle limited-length printf's. In should be NOT be used
590 * for string concatenation like printf("xyz %s %s", s1, s2).
592 * Engine will call Print for "print" and "echo"
594 void CPhPLibContext::Printf(const char *str
, ...)
599 if ( !g_curr_context
|| !g_curr_context
->m_curr_str_buffer
) {
603 vsnprintf(buf
, sizeof(buf
), str
, args
);
604 g_curr_context
->m_curr_str_buffer
->Write(buf
);
609 void CPhPLibContext::Print(const char *str
)
611 if ( !g_curr_context
|| !g_curr_context
->m_curr_str_buffer
) {
614 g_curr_context
->m_curr_str_buffer
->Write(str
);
619 CPhpFilter::CPhpFilter(CWebServerBase
*server
, CSession
*sess
,
620 const char *file
, CWriteStrBuffer
*buff
)
622 FILE *f
= fopen(file
, "r");
624 printf("ERROR: php can not open source file [%s]\n", file
);
627 if ( fseek(f
, 0, SEEK_END
) != 0 ) {
628 printf("ERROR: fseek failed on php source file [%s]\n", file
);
632 char *buf
= new char [size
+1];
634 // fread may actually read less if it is a CR-LF-file in Windows
635 size
= fread(buf
, 1, size
, f
);
638 char *scan_ptr
= buf
;
639 char *curr_code_end
= buf
;
640 while ( strlen(scan_ptr
) ) {
641 scan_ptr
= strstr(scan_ptr
, "<?php");
643 buff
->Write(curr_code_end
);
646 if ( scan_ptr
!= curr_code_end
) {
647 buff
->Write(curr_code_end
, scan_ptr
- curr_code_end
);
649 curr_code_end
= strstr(scan_ptr
, "?>");
650 if ( !curr_code_end
) {
653 curr_code_end
+= 2; // include "?>" in buffer
655 int len
= curr_code_end
- scan_ptr
;
657 CPhPLibContext
*context
= new CPhPLibContext(server
, scan_ptr
, len
);
659 #ifndef PHP_STANDALONE_EN
660 load_session_vars("HTTP_GET_VARS", sess
->m_get_vars
);
661 load_session_vars("_SESSION", sess
->m_vars
);
664 context
->Execute(buff
);
666 #ifndef PHP_STANDALONE_EN
667 save_session_vars(sess
->m_vars
);
672 scan_ptr
= curr_code_end
;
675 #ifndef PHP_STANDALONE_EN
676 sess
->m_get_vars
.clear();
684 * String buffer: almost same as regular 'string' class, but,
685 * without reallocation when full. Instead, new buffer is
686 * allocated, and added to list
688 CWriteStrBuffer::CWriteStrBuffer()
696 CWriteStrBuffer::~CWriteStrBuffer()
698 for(std::list
<char *>::iterator i
= m_buf_list
.begin(); i
!= m_buf_list
.end(); i
++) {
701 delete [] m_curr_buf
;
704 void CWriteStrBuffer::AllocBuf()
706 m_curr_buf
= new char [m_alloc_size
];
707 m_buf_ptr
= m_curr_buf
;
708 m_curr_buf_left
= m_alloc_size
;
711 void CWriteStrBuffer::Write(const char *s
, int len
)
716 m_total_length
+= len
;
719 if ( (len
+ 1) <= m_curr_buf_left
) {
720 strncpy(m_buf_ptr
, s
, len
);
722 m_curr_buf_left
-= len
;
725 memcpy(m_buf_ptr
, s
, m_curr_buf_left
);
726 int rem_len
= len
- m_curr_buf_left
;
727 s
+= m_curr_buf_left
;
730 m_buf_list
.push_back(m_curr_buf
);
736 void CWriteStrBuffer::CopyAll(char *dst_buffer
)
738 char *curr_ptr
= dst_buffer
;
739 int rem_size
= m_total_length
;
740 for(std::list
<char *>::iterator i
= m_buf_list
.begin(); i
!= m_buf_list
.end(); i
++) {
741 memcpy(curr_ptr
, *i
, m_alloc_size
);
742 rem_size
-= m_alloc_size
;
743 curr_ptr
+= m_alloc_size
;
746 memcpy(curr_ptr
, m_curr_buf
, rem_size
);
748 *(curr_ptr
+ rem_size
) = 0;
751 void load_session_vars(const char *target
, std::map
<std::string
, std::string
> &varmap
)
753 PHP_EXP_NODE
*sess_vars_exp_node
= get_var_node(target
);
754 PHP_VAR_NODE
*sess_vars
= sess_vars_exp_node
->var_si_node
->var
;
755 // i'm not building exp tree, node not needed
756 delete sess_vars_exp_node
;
757 cast_value_array(&sess_vars
->value
);
758 for(std::map
<std::string
, std::string
>::iterator i
= varmap
.begin(); i
!= varmap
.end(); i
++) {
759 PHP_VAR_NODE
*curr_var
= array_get_by_str_key(&sess_vars
->value
, i
->first
);
761 val
.type
= PHP_VAL_STRING
;
762 val
.str_val
= const_cast<char *>(i
->second
.c_str());
763 value_value_assign(&curr_var
->value
, &val
);
767 void save_session_vars(std::map
<std::string
, std::string
> &varmap
)
769 PHP_EXP_NODE
*sess_vars_exp_node
= get_var_node("_SESSION");
770 PHP_VAR_NODE
*sess_vars
= sess_vars_exp_node
->var_si_node
->var
;
772 delete sess_vars_exp_node
;
773 if ( sess_vars
->value
.type
!= PHP_VAL_ARRAY
) {
777 for(int i
= 0; i
< array_get_size(&sess_vars
->value
); i
++) {
778 std::string s
= array_get_ith_key(&sess_vars
->value
, i
);
779 PHP_VAR_NODE
*var
= array_get_by_str_key(&sess_vars
->value
, s
);
780 cast_value_str(&var
->value
);
781 varmap
[s
] = var
->value
.str_val
;
784 // File_checked_for_headers