/** * Returns whether this is an internal function * * @return boolean True if this is an internal function */ public function isInternal() { if ($this->reflectionSource instanceof ReflectionFunction) { return $this->reflectionSource->isInternal(); } else { return parent::isInternal(); } }
function dumpFuncInfo($name) { $funcInfo = new ReflectionFunction($name); var_dump($funcInfo->getName()); var_dump($funcInfo->isInternal()); var_dump($funcInfo->isUserDefined()); var_dump($funcInfo->getStartLine()); var_dump($funcInfo->getEndLine()); var_dump($funcInfo->getStaticVariables()); }
/** * @param string $name * @return bool */ protected function isInternalFunction($name) { try { $ref_func = new ReflectionFunction($name); return $ref_func->isInternal(); } catch (ReflectionException $e) { // ReflectionException: Function xxx() does not exist return false; } }
private function isPhpFunction(Link $link) { $functionName = $link->getDestination(); if (!$this->isMethodLink($functionName)) { return; } $functionName = substr($functionName, 0, -2); if (!function_exists($functionName)) { return false; } $functionReflection = new \ReflectionFunction($functionName); return $functionReflection->isInternal(); }
protected function addFunctions($parent, array $functions) { if (!empty($functions['internal'])) { $functions = $functions['internal']; } foreach ($functions as $ref) { if (is_string($ref)) { $ref = new \ReflectionFunction($ref); } if (!$ref->isInternal()) { return; } $name = getFunctionString($ref); $this->append($parent, array($name, $ref)); } }
public function testRegisterResetAndValues() { $this->assertFalse(Manager::overridden('natcasesort')); Manager::register('\\Skeetr\\Tests\\Runtime\\Example'); $function = new \ReflectionFunction('natcasesort'); $this->assertFalse($function->isInternal()); $this->assertSame('foo', natcasesort('foo')); $this->assertTrue(Manager::overridden('natcasesort')); $this->assertSame(1, Example::$test); Example::$test = 0; Manager::reset(); $this->assertSame(1, Example::$test); Example::$test = 0; Manager::reset('\\Skeetr\\Tests\\Runtime\\Example'); $this->assertSame(1, Example::$test); $this->assertTrue(false === Manager::reset('NotExists')); $expected = array('example' => array('test' => 1)); $this->assertSame($expected, Manager::values('\\Skeetr\\Tests\\Runtime\\Example')); $values = Manager::values('\\Skeetr\\Tests\\Runtime\\Example'); $this->assertSame(1, $values['example']['test']); }
/** * @return string */ private function ouptutUnusedFunctionsReport() { //prepare unused functions report $functions = get_defined_functions(); $functions = array_filter($functions['user'], 'strtolower'); $calledFunctions = array_filter($this->calledFunctions, 'strtolower'); $deprecatedFunctions = array_filter(array_keys(code_review::getDeprecatedFunctionsList($this->maxVersion)), 'strtolower'); $functions = array_diff($functions, $calledFunctions, $deprecatedFunctions); foreach ($functions as $key => $function) { if (function_exists($function)) { $reflectionFunction = new ReflectionFunction($function); if (!$reflectionFunction->isInternal()) { continue; } unset($reflectionFunction); } unset($functions[$key]); } sort($functions); //unused functions report $result = "Not called but defined funcions:\n"; $baseLenght = strlen(elgg_get_root_path()); foreach (array_values($functions) as $functionName) { $reflectionFunction = new ReflectionFunction($functionName); $path = substr($reflectionFunction->getFileName(), $baseLenght); if (strpos($path, 'engine') !== 0) { continue; } $result .= "{$functionName} \t{$path}:{$reflectionFunction->getStartLine()}\n"; } return $result; }
private static function checkRule($_rule, $val, $data, $db = null) { if (!$db) { $db = WoniuLoader::instance()->database(); } $matches = self::getCheckRuleInfo($_rule); $_rule = $matches[1]; $args = $matches[2]; switch ($_rule) { case 'required': return !empty($val); case 'match': return isset($args[0]) && isset($data[$args[0]]) ? $val && $val == $data[$args[0]] : false; case 'equal': return isset($args[0]) ? $val && $val == $args[0] : false; case 'enum': return in_array($val, $args); case 'unique': #比如unique[user.name] , unique[user.name,id:1] if (!$val || !count($args)) { return false; } $_info = explode('.', $args[0]); if (count($_info) != 2) { return false; } $table = $_info[0]; $col = $_info[1]; if (isset($args[1])) { $_id_info = explode(':', $args[1]); if (count($_id_info) != 2) { return false; } $id_col = $_id_info[0]; $id = $_id_info[1]; $id = stripos($id, '#') === 0 ? WoniuInput::get_post(substr($id, 1)) : $id; $where = array($col => $val, "{$id_col} <>" => $id); } else { $where = array($col => $val); } return !$db->where($where)->from($table)->count_all_results(); case 'exists': #比如exists[user.name] , exists[user.name,type:1], exists[user.name,type:1,sex:#sex] if (!$val || !count($args)) { return false; } $_info = explode('.', $args[0]); if (count($_info) != 2) { return false; } $table = $_info[0]; $col = $_info[1]; $where = array($col => $val); if (count($args) > 1) { foreach (array_slice($args, 1) as $v) { $_id_info = explode(':', $v); if (count($_id_info) != 2) { continue; } $id_col = $_id_info[0]; $id = $_id_info[1]; $id = stripos($id, '#') === 0 ? WoniuInput::get_post(substr($id, 1)) : $id; $where[$id_col] = $id; } } return $db->where($where)->from($table)->count_all_results(); case 'min_len': return isset($args[0]) ? mb_strlen($val, 'UTF-8') >= intval($args[0]) : false; case 'max_len': return isset($args[0]) ? mb_strlen($val, 'UTF-8') <= intval($args[0]) : false; case 'range_len': return count($args) == 2 ? mb_strlen($val, 'UTF-8') >= intval($args[0]) && mb_strlen($val, 'UTF-8') <= intval($args[1]) : false; case 'len': return isset($args[0]) ? mb_strlen($val, 'UTF-8') == intval($args[0]) : false; case 'min': return isset($args[0]) && is_numeric($val) ? $val >= $args[0] : false; case 'max': return isset($args[0]) && is_numeric($val) ? $val <= $args[0] : false; case 'range': return count($args) == 2 && is_numeric($val) ? $val >= $args[0] && $val <= $args[1] : false; case 'alpha': #纯字母 return !preg_match('/[^A-Za-z]+/', $val); case 'alpha_num': #纯字母和数字 return !preg_match('/[^A-Za-z0-9]+/', $val); case 'alpha_dash': #纯字母和数字和下划线和- return !preg_match('/[^A-Za-z0-9_-]+/', $val); case 'alpha_start': #以字母开头 return preg_match('/^[A-Za-z]+/', $val); case 'num': #纯数字 return !preg_match('/[^0-9]+/', $val); case 'int': #整数 return preg_match('/^([-+]?[1-9]\\d*|0)$/', $val); case 'float': #小数 return preg_match('/^([1-9]\\d*|0)\\.\\d+$/', $val); case 'numeric': #数字-1,1.2,+3,4e5 return is_numeric($val); case 'natural': #自然数0,1,2,3,12,333 return preg_match('/^([1-9]\\d*|0)$/', $val); case 'natural_no_zero': #自然数不包含0 return preg_match('/^[1-9]\\d*$/', $val); case 'email': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$/', $val) : $args[0]; case 'url': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^http[s]?:\\/\\/[A-Za-z0-9]+\\.[A-Za-z0-9]+[\\/=\\?%\\-&_~`@[\\]\':+!]*([^<>\\"])*$/', $val) : $args[0]; case 'qq': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[1-9][0-9]{4,}$/', $val) : $args[0]; case 'phone': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^(?:\\d{3}-?\\d{8}|\\d{4}-?\\d{7})$/', $val) : $args[0]; case 'mobile': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(14[0-9]{1}))+\\d{8})$/', $val) : $args[0]; case 'zipcode': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[1-9]\\d{5}(?!\\d)$/', $val) : $args[0]; case 'idcard': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^\\d{14}(\\d{4}|(\\d{3}[xX])|\\d{1})$/', $val) : $args[0]; case 'ip': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/', $val) : $args[0]; case 'chs': $count = implode(',', array_slice($args, 1, 2)); $count = empty($count) ? '1,' : $count; $can_empty = isset($args[0]) && $args[0] == 'true'; return !empty($val) ? preg_match('/^[\\x{4e00}-\\x{9fa5}]{' . $count . '}$/u', $val) : $can_empty; case 'date': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$/', $val) : $args[0]; case 'time': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^(([0-1][0-9])|([2][0-3])):([0-5][0-9])(:([0-5][0-9]))$/', $val) : $args[0]; case 'datetime': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30))) (([0-1][0-9])|([2][0-3])):([0-5][0-9])(:([0-5][0-9]))$/', $val) : $args[0]; case 'reg': #正则表达式验证,reg[/^[\]]$/i] /** * 模式修正符说明: i 表示在和模式进行匹配进不区分大小写 m 将模式视为多行,使用^和$表示任何一行都可以以正则表达式开始或结束 s 如果没有使用这个模式修正符号,元字符中的"."默认不能表示换行符号,将字符串视为单行 x 表示模式中的空白忽略不计 e 正则表达式必须使用在preg_replace替换字符串的函数中时才可以使用(讲这个函数时再说) A 以模式字符串开头,相当于元字符^ Z 以模式字符串结尾,相当于元字符$ U 正则表达式的特点:就是比较“贪婪”,使用该模式修正符可以取消贪婪模式 */ return !empty($args[0]) ? preg_match($args[0], $val) : false; /** * set set_post不参与验证,返回true跳过 * * 说明: * set用于设置在验证数据前对数据进行处理的函数或者方法 * set_post用于设置在验证数据后对数据进行处理的函数或者方法 * 如果设置了set,数据在验证的时候验证的是处理过的数据 * 如果设置了set_post,可以通过第三个参数$data接收数据:$this->checkData($rule, $_POST, $data),$data是验证通过并经过set_post处理后的数据 * set和set_post后面是一个或者多个函数或者方法,多个逗号分割 * 注意: * 1.无论是函数或者方法都必须有一个字符串返回 * 2.如果是系统函数,系统会传递当前值给系统函数,因此系统函数必须是至少接受一个字符串参数,比如md5,trim * 3.如果是自定义的函数,系统会传递当前值和全部数据给自定义的函数,因此自定义函数可以接收两个参数第一个是值,第二个是全部数据$data * 4.如果是类的方法写法是:类名称::方法名 (方法静态动态都可以,public,private,都可以) */ /** * set set_post不参与验证,返回true跳过 * * 说明: * set用于设置在验证数据前对数据进行处理的函数或者方法 * set_post用于设置在验证数据后对数据进行处理的函数或者方法 * 如果设置了set,数据在验证的时候验证的是处理过的数据 * 如果设置了set_post,可以通过第三个参数$data接收数据:$this->checkData($rule, $_POST, $data),$data是验证通过并经过set_post处理后的数据 * set和set_post后面是一个或者多个函数或者方法,多个逗号分割 * 注意: * 1.无论是函数或者方法都必须有一个字符串返回 * 2.如果是系统函数,系统会传递当前值给系统函数,因此系统函数必须是至少接受一个字符串参数,比如md5,trim * 3.如果是自定义的函数,系统会传递当前值和全部数据给自定义的函数,因此自定义函数可以接收两个参数第一个是值,第二个是全部数据$data * 4.如果是类的方法写法是:类名称::方法名 (方法静态动态都可以,public,private,都可以) */ case 'set': case 'set_post': return true; default: $_args = array_merge(array($val, $data), $args); $matches = self::getCheckRuleInfo($_rule); $func = $matches[1]; $args = $matches[2]; if (function_exists($func)) { $reflection = new ReflectionFunction($func); //如果是系统函数 if ($reflection->isInternal()) { $_args = isset($_args[0]) ? array($_args[0]) : array(); } } return self::callFunc($_rule, $_args); } return false; }
$funcs = get_defined_functions(); foreach ($funcs['internal'] as $func) { $rf = new ReflectionFunction($func); $info = array('kind' => 'f', 'namespace' => $rf->getNamespaceName()); $params = array(); foreach ($rf->getParameters() as $rp) { $class = ''; if (!defined('HHVM_VERSION')) { $class = $rp->getClass(); } $param = ''; if ($class) { $param = $class->getName() . ' '; } elseif ($rp->isArray()) { $param = 'array '; } $param .= '$' . $rp->getName(); if ($rp->isOptional() && $rf->isUserDefined()) { $param .= '=' . json_encode($rp->getDefaultValue()); } $params[] = $param; } $info['type'] = '(' . implode(', ', $params) . ')'; if ($rf->isInternal()) { $filename = '(ext-' . $rf->getExtensionName() . ')'; } else { $filename = str_replace($base, '', $rf->getFileName()); } fwrite($fp, implode("\t", array($rf->getName(), $filename, $rf->getStartLine() . ';"', '')) . $build($info) . PHP_EOL); } });
<pre> <?php function sayHello($name, $h) { static $count = 0; return "<h{$h}>Hello, {$name}</h{$h}>"; } // Обзор функции Reflection::export(new ReflectionFunction('sayHello')); // Создание экземпляра класса ReflectionFunction $func = new ReflectionFunction('sayHello'); // Вывод основной информации printf("<p>===> %s функция '%s'\n" . " объявлена в %s\n" . " строки с %d по %d\n", $func->isInternal() ? 'Internal' : 'User-defined', $func->getName(), $func->getFileName(), $func->getStartLine(), $func->getEndline()); // Вывод статических переменных, если они есть if ($statics = $func->getStaticVariables()) { printf("<p>---> Статическая переменная: %s\n", var_export($statics, 1)); } // Вызов функции printf("<p>---> Результат вызова: "); $result = $func->invoke("John", "1"); echo $result; ?> </pre>
<?php /** hoho */ function test($a, $b = 1, $c = "") { static $var = 1; } $func = new ReflectionFunction("test"); var_dump($func->export("test")); echo "--getName--\n"; var_dump($func->getName()); echo "--isInternal--\n"; var_dump($func->isInternal()); echo "--isUserDefined--\n"; var_dump($func->isUserDefined()); echo "--getFilename--\n"; var_dump($func->getFilename()); echo "--getStartline--\n"; var_dump($func->getStartline()); echo "--getEndline--\n"; var_dump($func->getEndline()); echo "--getDocComment--\n"; var_dump($func->getDocComment()); echo "--getStaticVariables--\n"; var_dump($func->getStaticVariables()); echo "--invoke--\n"; var_dump($func->invoke(array(1, 2, 3))); echo "--invokeArgs--\n"; var_dump($func->invokeArgs(array(1, 2, 3)));
/** * Get all info about function * @param string|function $functionName Function or function name * @return array|bool */ protected static function _getFunction($functionName) { if (is_string($functionName) && !function_exists($functionName)) { return false; } elseif (empty($functionName)) { return false; } // create ReflectionFunction instance $func = new ReflectionFunction($functionName); // get basic function info $result = array(); $result['name'] = $func->getName(); $result['type'] = $func->isInternal() ? 'internal' : 'user-defined'; if (method_exists($func, 'getNamespaceName') && ($namespace = $func->getNamespaceName())) { $result['namespace'] = $namespace; } if ($func->isDeprecated()) { $result['deprecated'] = true; } if ($static = $func->getStaticVariables()) { $result['static'] = $static; } if ($reference = $func->returnsReference()) { $result['reference'] = $reference; } if ($path = $func->getFileName()) { $result['path'] = $path . ' ' . $func->getStartLine() . '/' . $func->getEndLine(); } if ($parameters = $func->getParameters()) { $result['parameters'] = self::_getParams($parameters, $func->isInternal()); } // get function source if (isset($result['path']) && $result['path']) { $result['comment'] = $func->getDocComment(); $startLine = $func->getStartLine(); $endLine = $func->getEndLine(); $source = @file($func->getFileName()); if ($startLine && $source) { $from = (int) ($startLine - 1); $to = (int) ($endLine - $startLine + 1); $slice = array_slice($source, $from, $to); $result['source::source'] = implode('', $slice); } } return $result; }
/** * Given a user-defined PHP function, create a PHP 'wrapper' function that can * be exposed as xmlrpc method from an xmlrpc_server object and called from remote * clients (as well as its corresponding signature info). * * Since php is a typeless language, to infer types of input and output parameters, * it relies on parsing the javadoc-style comment block associated with the given * function. Usage of xmlrpc native types (such as datetime.dateTime.iso8601 and base64) * in the @param tag is also allowed, if you need the php function to receive/send * data in that particular format (note that base64 encoding/decoding is transparently * carried out by the lib, while datetime vals are passed around as strings) * * Known limitations: * - requires PHP 5.0.3 + * - only works for user-defined functions, not for PHP internal functions * (reflection does not support retrieving number/type of params for those) * - functions returning php objects will generate special xmlrpc responses: * when the xmlrpc decoding of those responses is carried out by this same lib, using * the appropriate param in php_xmlrpc_decode, the php objects will be rebuilt. * In short: php objects can be serialized, too (except for their resource members), * using this function. * Other libs might choke on the very same xml that will be generated in this case * (i.e. it has a nonstandard attribute on struct element tags) * - usage of javadoc @param tags using param names in a different order from the * function prototype is not considered valid (to be fixed?) * * Note that since rel. 2.0RC3 the preferred method to have the server call 'standard' * php functions (ie. functions not expecting a single xmlrpcmsg obj as parameter) * is by making use of the functions_parameters_type class member. * * @param string $funcname the name of the PHP user function to be exposed as xmlrpc method; array($obj, 'methodname') and array('class', 'methodname') are ok too * @param string $newfuncname (optional) name for function to be created * @param array $extra_options (optional) array of options for conversion. valid values include: * bool return_source when true, php code w. function definition will be returned, not evaluated * bool encode_php_objs let php objects be sent to server using the 'improved' xmlrpc notation, so server can deserialize them as php objects * bool decode_php_objs --- WARNING !!! possible security hazard. only use it with trusted servers --- * bool suppress_warnings remove from produced xml any runtime warnings due to the php function being invoked * @return false on error, or an array containing the name of the new php function, * its signature and docs, to be used in the server dispatch map * * @todo decide how to deal with params passed by ref: bomb out or allow? * @todo finish using javadoc info to build method sig if all params are named but out of order * @todo add a check for params of 'resource' type * @todo add some trigger_errors / error_log when returning false? * @todo what to do when the PHP function returns NULL? we are currently returning an empty string value... * @todo add an option to suppress php warnings in invocation of user function, similar to server debug level 3? * @todo if $newfuncname is empty, we could use create_user_func instead of eval, as it is possibly faster * @todo add a verbatim_object_copy parameter to allow avoiding the same obj instance? */ function wrap_php_function($funcname, $newfuncname = '', $extra_options = array()) { $buildit = isset($extra_options['return_source']) ? !$extra_options['return_source'] : true; $prefix = isset($extra_options['prefix']) ? $extra_options['prefix'] : 'xmlrpc'; $encode_php_objects = isset($extra_options['encode_php_objs']) ? (bool) $extra_options['encode_php_objs'] : false; $decode_php_objects = isset($extra_options['decode_php_objs']) ? (bool) $extra_options['decode_php_objs'] : false; $catch_warnings = isset($extra_options['suppress_warnings']) && $extra_options['suppress_warnings'] ? '@' : ''; if (version_compare(phpversion(), '5.0.3') == -1) { // up to php 5.0.3 some useful reflection methods were missing error_log('XML-RPC: cannot not wrap php functions unless running php version bigger than 5.0.3'); return false; } $exists = false; if (is_string($funcname) && strpos($funcname, '::') !== false) { $funcname = explode('::', $funcname); } if (is_array($funcname)) { if (count($funcname) < 2 || !is_string($funcname[0]) && !is_object($funcname[0])) { error_log('XML-RPC: syntax for function to be wrapped is wrong'); return false; } if (is_string($funcname[0])) { $plainfuncname = implode('::', $funcname); } elseif (is_object($funcname[0])) { $plainfuncname = get_class($funcname[0]) . '->' . $funcname[1]; } $exists = method_exists($funcname[0], $funcname[1]); if (!$exists && version_compare(phpversion(), '5.1') < 0) { // workaround for php 5.0: static class methods are not seen by method_exists $exists = is_callable($funcname); } } else { $plainfuncname = $funcname; $exists = function_exists($funcname); } if (!$exists) { error_log('XML-RPC: function to be wrapped is not defined: ' . $plainfuncname); return false; } else { // determine name of new php function if ($newfuncname == '') { if (is_array($funcname)) { if (is_string($funcname[0])) { $xmlrpcfuncname = "{$prefix}_" . implode('_', $funcname); } else { $xmlrpcfuncname = "{$prefix}_" . get_class($funcname[0]) . '_' . $funcname[1]; } } else { $xmlrpcfuncname = "{$prefix}_{$funcname}"; } } else { $xmlrpcfuncname = $newfuncname; } while ($buildit && function_exists($xmlrpcfuncname)) { $xmlrpcfuncname .= 'x'; } // start to introspect PHP code if (is_array($funcname)) { $func = new ReflectionMethod($funcname[0], $funcname[1]); if ($func->isPrivate()) { error_log('XML-RPC: method to be wrapped is private: ' . $plainfuncname); return false; } if ($func->isProtected()) { error_log('XML-RPC: method to be wrapped is protected: ' . $plainfuncname); return false; } if ($func->isConstructor()) { error_log('XML-RPC: method to be wrapped is the constructor: ' . $plainfuncname); return false; } // php 503 always says isdestructor = true... if (version_compare(phpversion(), '5.0.3') != 0 && $func->isDestructor()) { error_log('XML-RPC: method to be wrapped is the destructor: ' . $plainfuncname); return false; } if ($func->isAbstract()) { error_log('XML-RPC: method to be wrapped is abstract: ' . $plainfuncname); return false; } /// @todo add more checks for static vs. nonstatic? } else { $func = new ReflectionFunction($funcname); } if ($func->isInternal()) { // Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs // instead of getparameters to fully reflect internal php functions ? error_log('XML-RPC: function to be wrapped is internal: ' . $plainfuncname); return false; } // retrieve parameter names, types and description from javadoc comments // function description $desc = ''; // type of return val: by default 'any' $returns = $GLOBALS['xmlrpcValue']; // desc of return val $returnsDocs = ''; // type + name of function parameters $paramDocs = array(); $docs = $func->getDocComment(); if ($docs != '') { $docs = explode("\n", $docs); $i = 0; foreach ($docs as $doc) { $doc = trim($doc, " \r\t/*"); if (strlen($doc) && strpos($doc, '@') !== 0 && !$i) { if ($desc) { $desc .= "\n"; } $desc .= $doc; } elseif (strpos($doc, '@param') === 0) { // syntax: @param type [$name] desc if (preg_match('/@param\\s+(\\S+)(\\s+\\$\\S+)?\\s+(.+)/', $doc, $matches)) { if (strpos($matches[1], '|')) { //$paramDocs[$i]['type'] = explode('|', $matches[1]); $paramDocs[$i]['type'] = 'mixed'; } else { $paramDocs[$i]['type'] = $matches[1]; } $paramDocs[$i]['name'] = trim($matches[2]); $paramDocs[$i]['doc'] = $matches[3]; } $i++; } elseif (strpos($doc, '@return') === 0) { // syntax: @return type desc //$returns = preg_split('/\s+/', $doc); if (preg_match('/@return\\s+(\\S+)\\s+(.+)/', $doc, $matches)) { $returns = php_2_xmlrpc_type($matches[1]); if (isset($matches[2])) { $returnsDocs = $matches[2]; } } } } } // execute introspection of actual function prototype $params = array(); $i = 0; foreach ($func->getParameters() as $paramobj) { $params[$i] = array(); $params[$i]['name'] = '$' . $paramobj->getName(); $params[$i]['isoptional'] = $paramobj->isOptional(); $i++; } // start building of PHP code to be eval'd $innercode = ''; $i = 0; $parsvariations = array(); $pars = array(); $pnum = count($params); foreach ($params as $param) { if (isset($paramDocs[$i]['name']) && $paramDocs[$i]['name'] && strtolower($paramDocs[$i]['name']) != strtolower($param['name'])) { // param name from phpdoc info does not match param definition! $paramDocs[$i]['type'] = 'mixed'; } if ($param['isoptional']) { // this particular parameter is optional. save as valid previous list of parameters $innercode .= "if (\$paramcount > {$i}) {\n"; $parsvariations[] = $pars; } $innercode .= "\$p{$i} = \$msg->getParam({$i});\n"; if ($decode_php_objects) { $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p{$i} = \$p{$i}->scalarval(); else \$p{$i} = php_{$prefix}_decode(\$p{$i}, array('decode_php_objs'));\n"; } else { $innercode .= "if (\$p{$i}->kindOf() == 'scalar') \$p{$i} = \$p{$i}->scalarval(); else \$p{$i} = php_{$prefix}_decode(\$p{$i});\n"; } $pars[] = "\$p{$i}"; $i++; if ($param['isoptional']) { $innercode .= "}\n"; } if ($i == $pnum) { // last allowed parameters combination $parsvariations[] = $pars; } } $sigs = array(); $psigs = array(); if (count($parsvariations) == 0) { // only known good synopsis = no parameters $parsvariations[] = array(); $minpars = 0; } else { $minpars = count($parsvariations[0]); } if ($minpars) { // add to code the check for min params number // NB: this check needs to be done BEFORE decoding param values $innercode = "\$paramcount = \$msg->getNumParams();\n" . "if (\$paramcount < {$minpars}) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}');\n" . $innercode; } else { $innercode = "\$paramcount = \$msg->getNumParams();\n" . $innercode; } $innercode .= "\$np = false;\n"; // since there are no closures in php, if we are given an object instance, // we store a pointer to it in a global var... if (is_array($funcname) && is_object($funcname[0])) { $GLOBALS['xmlrpcWPFObjHolder'][$xmlrpcfuncname] =& $funcname[0]; $innercode .= "\$obj =& \$GLOBALS['xmlrpcWPFObjHolder']['{$xmlrpcfuncname}'];\n"; $realfuncname = '$obj->' . $funcname[1]; } else { $realfuncname = $plainfuncname; } foreach ($parsvariations as $pars) { $innercode .= "if (\$paramcount == " . count($pars) . ") \$retval = {$catch_warnings}{$realfuncname}(" . implode(',', $pars) . "); else\n"; // build a 'generic' signature (only use an appropriate return type) $sig = array($returns); $psig = array($returnsDocs); for ($i = 0; $i < count($pars); $i++) { if (isset($paramDocs[$i]['type'])) { $sig[] = php_2_xmlrpc_type($paramDocs[$i]['type']); } else { $sig[] = $GLOBALS['xmlrpcValue']; } $psig[] = isset($paramDocs[$i]['doc']) ? $paramDocs[$i]['doc'] : ''; } $sigs[] = $sig; $psigs[] = $psig; } $innercode .= "\$np = true;\n"; $innercode .= "if (\$np) return new {$prefix}resp(0, {$GLOBALS['xmlrpcerr']['incorrect_params']}, '{$GLOBALS['xmlrpcstr']['incorrect_params']}'); else {\n"; //$innercode .= "if (\$_xmlrpcs_error_occurred) return new xmlrpcresp(0, $GLOBALS['xmlrpcerr']user, \$_xmlrpcs_error_occurred); else\n"; $innercode .= "if (is_a(\$retval, '{$prefix}resp')) return \$retval; else\n"; if ($returns == $GLOBALS['xmlrpcDateTime'] || $returns == $GLOBALS['xmlrpcBase64']) { $innercode .= "return new {$prefix}resp(new {$prefix}val(\$retval, '{$returns}'));"; } else { if ($encode_php_objects) { $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval, array('encode_php_objs')));\n"; } else { $innercode .= "return new {$prefix}resp(php_{$prefix}_encode(\$retval));\n"; } } // shall we exclude functions returning by ref? // if($func->returnsReference()) // return false; $code = "function {$xmlrpcfuncname}(\$msg) {\n" . $innercode . "}\n}"; //print_r($code); if ($buildit) { $allOK = 0; eval($code . '$allOK=1;'); // alternative //$xmlrpcfuncname = create_function('$m', $innercode); if (!$allOK) { error_log('XML-RPC: could not create function ' . $xmlrpcfuncname . ' to wrap php function ' . $plainfuncname); return false; } } /// @todo examine if $paramDocs matches $parsvariations and build array for /// usage as method signature, plus put together a nice string for docs $ret = array('function' => $xmlrpcfuncname, 'signature' => $sigs, 'docstring' => $desc, 'signature_docs' => $psigs, 'source' => $code); return $ret; } }
/** * Shows a backtrace item. * * @param int $n Count. * @param array $trace Trace result. * * @return void */ protected function _showTraceItem($n, $trace) { echo '<tr><td align="right" valign="top" class="error-number">#', $n, '</td><td>'; if (isset($trace['class'])) { if (preg_match('/^Phalcon/', $trace['class'])) { echo '<span class="error-class"><a target="_new" href="http://docs.phalconphp.com/en/latest/api/', str_replace('\\', '_', $trace['class']), '.html">', $trace['class'], '</a></span>'; } else { $classReflection = new \ReflectionClass($trace['class']); if ($classReflection->isInternal()) { echo '<span class="error-class"><a target="_new" href="http://php.net/manual/en/class.', str_replace('_', '-', strtolower($trace['class'])), '.php">', $trace['class'], '</a></span>'; } else { echo '<span class="error-class">', $trace['class'], '</span>'; } } echo $trace['type']; } if (isset($trace['class'])) { echo '<span class="error-function">', $trace['function'], '</span>'; } else { if (function_exists($trace['function'])) { $functionReflection = new \ReflectionFunction($trace['function']); if ($functionReflection->isInternal()) { echo '<span class="error-function"><a target="_new" href="http://php.net/manual/en/function.', str_replace('_', '-', $trace['function']), '.php">', $trace['function'], '</a></span>'; } else { echo '<span class="error-function">', $trace['function'], '</span>'; } } else { echo '<span class="error-function">', $trace['function'], '</span>'; } } if (isset($trace['args'])) { $this->_echoArgs($trace['args']); } if (isset($trace['file'])) { echo '<br/><span class="error-file">', $trace['file'], ' (', $trace['line'], ')</span>'; } echo '</td></tr>'; if ($this->_showFiles) { if (isset($trace['file'])) { $this->_echoFile($trace['file'], $trace['line']); } } }
/** * maps function and all parameters of function using reflection. returns object map * as object throws error if mapping was not successful * * @error 14105 * @param string $function expects function name * @return null|XO * @throws Xapp_Rpc_Smd_Exception */ protected function mapFunction($function) { try { $tmp = array(); $obj = new XO(); $function = new ReflectionFunction($function); if ($function->isInternal()) { throw new Xapp_Rpc_Smd_Exception(xapp_sprintf(_("function: %s can not be mapped since it is internal"), $function), 1410502); } $obj->transport = null; $obj->target = null; $method = $this->mapMethod($function); if (xapp_get_option(self::SERVICE_DESCRIPTION, $this) && isset($method->description)) { $obj->description = $method->description; } if (isset($method->returns)) { $obj->returns = $method->returns; } $i = 0; foreach ($function->getParameters() as $p) { $params = $this->mapParameter($p); if (isset($method->params) && isset($method->params['type'][$i])) { $params->type = $method->params['type'][$i]; } if (isset($method->params) && isset($method->params['description'][$i]) && xapp_get_option(self::SERVICE_DESCRIPTION, $this)) { $params->description = $method->params['description'][$i]; } $tmp[] = $params; $i++; } $obj->parameters = $tmp; return $obj; } catch (ReflectionException $e) { throw new Xapp_Rpc_Smd_Exception(xapp_sprintf(_("unable to map function: %s due to reflection error: %d, %s"), $function, $e->getCode(), $e->getMessage()), 1410501); } }
/** * ensures that the given callable is really callable * * Internal functions like strlen() or is_string() require an *exact* amount * of arguments. If they receive too many arguments they just report an error. * This is a problem when you pass such a function as callable to a place * where it will receive more than it's exact amount of arguments. * * @param callable $callable * @return callable * @since 4.0.0 */ function ensureCallable(callable $callable) : callable { if (!is_string($callable)) { return $callable; } static $wrappedFunctions = []; if (isset($wrappedFunctions[$callable])) { return $wrappedFunctions[$callable]; } $function = new \ReflectionFunction($callable); if (!$function->isInternal()) { return $callable; } $signature = $arguments = ''; foreach ($function->getParameters() as $position => $param) { $signature .= ', ' . ($param->isPassedByReference() ? '&' : '') . '$_' . $position . ($param->isOptional() ? '= null' : ''); $arguments .= ', $_' . $position; } $wrappedFunctions[$callable] = eval('return function(' . substr($signature, 2) . ') { return ' . $callable . '(' . substr($arguments, 2) . '); };'); return $wrappedFunctions[$callable]; }
private static function checkRule($_rule, $val, $data, $db = null) { if (!$db) { $db = MpLoader::instance()->database(); } $matches = self::getCheckRuleInfo($_rule); $_rule = $matches[1]; $args = $matches[2]; switch ($_rule) { case 'required': return !empty($val); case 'match': return isset($args[0]) && isset($data[$args[0]]) ? $val && $val == $data[$args[0]] : false; case 'equal': return isset($args[0]) ? $val && $val == $args[0] : false; case 'enum': return in_array($val, $args); case 'unique': if (!$val || !count($args)) { return false; } $_info = explode('.', $args[0]); if (count($_info) != 2) { return false; } $table = $_info[0]; $col = $_info[1]; if (isset($args[1])) { $_id_info = explode(':', $args[1]); if (count($_id_info) != 2) { return false; } $id_col = $_id_info[0]; $id = $_id_info[1]; $id = stripos($id, '#') === 0 ? MpInput::get_post(substr($id, 1)) : $id; $where = array($col => $val, "{$id_col} <>" => $id); } else { $where = array($col => $val); } return !$db->where($where)->from($table)->count_all_results(); case 'exists': if (!$val || !count($args)) { return false; } $_info = explode('.', $args[0]); if (count($_info) != 2) { return false; } $table = $_info[0]; $col = $_info[1]; $where = array($col => $val); if (count($args) > 1) { foreach (array_slice($args, 1) as $v) { $_id_info = explode(':', $v); if (count($_id_info) != 2) { continue; } $id_col = $_id_info[0]; $id = $_id_info[1]; $id = stripos($id, '#') === 0 ? MpInput::get_post(substr($id, 1)) : $id; $where[$id_col] = $id; } } return $db->where($where)->from($table)->count_all_results(); case 'min_len': return isset($args[0]) ? mb_strlen($val, 'UTF-8') >= intval($args[0]) : false; case 'max_len': return isset($args[0]) ? mb_strlen($val, 'UTF-8') <= intval($args[0]) : false; case 'range_len': return count($args) == 2 ? mb_strlen($val, 'UTF-8') >= intval($args[0]) && mb_strlen($val, 'UTF-8') <= intval($args[1]) : false; case 'len': return isset($args[0]) ? mb_strlen($val, 'UTF-8') == intval($args[0]) : false; case 'min': return isset($args[0]) && is_numeric($val) ? $val >= $args[0] : false; case 'max': return isset($args[0]) && is_numeric($val) ? $val <= $args[0] : false; case 'range': return count($args) == 2 && is_numeric($val) ? $val >= $args[0] && $val <= $args[1] : false; case 'alpha': return !preg_match('/[^A-Za-z]+/', $val); case 'alpha_num': return !preg_match('/[^A-Za-z0-9]+/', $val); case 'alpha_dash': return !preg_match('/[^A-Za-z0-9_-]+/', $val); case 'alpha_start': return preg_match('/^[A-Za-z]+/', $val); case 'num': return !preg_match('/[^0-9]+/', $val); case 'int': return preg_match('/^([-+]?[1-9]\\d*|0)$/', $val); case 'float': return preg_match('/^([1-9]\\d*|0)\\.\\d+$/', $val); case 'numeric': return is_numeric($val); case 'natural': return preg_match('/^([1-9]\\d*|0)$/', $val); case 'natural_no_zero': return preg_match('/^[1-9]\\d*$/', $val); case 'email': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$/', $val) : $args[0]; case 'url': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^http[s]?:\\/\\/[A-Za-z0-9]+\\.[A-Za-z0-9]+[\\/=\\?%\\-&_~`@[\\]\':+!]*([^<>\\"])*$/', $val) : $args[0]; case 'qq': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[1-9][0-9]{4,}$/', $val) : $args[0]; case 'phone': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^(?:\\d{3}-?\\d{8}|\\d{4}-?\\d{7})$/', $val) : $args[0]; case 'mobile': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(14[0-9]{1}))+\\d{8})$/', $val) : $args[0]; case 'zipcode': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[1-9]\\d{5}(?!\\d)$/', $val) : $args[0]; case 'idcard': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^\\d{14}(\\d{4}|(\\d{3}[xX])|\\d{1})$/', $val) : $args[0]; case 'ip': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$/', $val) : $args[0]; case 'chs': $count = implode(',', array_slice($args, 1, 2)); $count = empty($count) ? '1,' : $count; $can_empty = isset($args[0]) && $args[0] == 'true'; return !empty($val) ? preg_match('/^[\\x{4e00}-\\x{9fa5}]{' . $count . '}$/u', $val) : $can_empty; case 'date': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$/', $val) : $args[0]; case 'time': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^(([0-1][0-9])|([2][0-3])):([0-5][0-9])(:([0-5][0-9]))$/', $val) : $args[0]; case 'datetime': $args[0] = isset($args[0]) && $args[0] == 'true' ? TRUE : false; return !empty($val) ? preg_match('/^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30))) (([0-1][0-9])|([2][0-3])):([0-5][0-9])(:([0-5][0-9]))$/', $val) : $args[0]; case 'reg': return !empty($args[0]) ? preg_match($args[0], $val) : false; case 'set': case 'set_post': return true; default: $_args = array_merge(array($val, $data), $args); $matches = self::getCheckRuleInfo($_rule); $func = $matches[1]; $args = $matches[2]; if (function_exists($func)) { $reflection = new ReflectionFunction($func); if ($reflection->isInternal()) { $_args = isset($_args[0]) ? array($_args[0]) : array(); } } return self::callFunc($_rule, $_args); } return false; }
function show_info($function, $basic = 0) { $func = new ReflectionFunction($function); $ret = ''; $ret .= "<pre><strong>Information:</strong>\n" . var_export($func->getDocComment(), 1) . "</pre>\n"; if ($basic) { $ret .= "<pre><pre>===> The " . ($func->isInternal() ? 'internal' : 'user-defined') . " function '" . $func->getName() . "'\n" . "\tdeclared in " . $func->getFileName() . "\n\tlines " . $func->getStartLine() . " to " . $func->getEndline() . "</pre>\n"; } return $ret; }
/** * Shows a backtrace item * * @param int $n * @param array $trace */ protected function _showTraceItem($n, $trace) { echo '<tr><td align="right" valign="top" class="error-number">#', $n, '</td><td>'; if (isset($trace['class'])) { if (preg_match('/^Phalcon/', $trace['class'])) { echo '<span class="error-class"><a target="_new" href="http://docs.phalconphp.com/en/latest/api/', str_replace('\\', '_', $trace['class']), '.html">', $trace['class'], '</a></span>'; } else { $classReflection = new \ReflectionClass($trace['class']); if ($classReflection->isInternal()) { echo '<span class="error-class"><a target="_new" href="http://php.net/manual/en/class.', str_replace('_', '-', strtolower($trace['class'])), '.php">', $trace['class'], '</a></span>'; } else { echo '<span class="error-class">', $trace['class'], '</span>'; } } echo $trace['type']; } if (isset($trace['class'])) { echo '<span class="error-function">', $trace['function'], '</span>'; } else { if (function_exists($trace['function'])) { $functionReflection = new \ReflectionFunction($trace['function']); if ($functionReflection->isInternal()) { echo '<span class="error-function"><a target="_new" href="http://php.net/manual/en/function.', str_replace('_', '-', $trace['function']), '.php">', $trace['function'], '</a></span>'; } else { echo '<span class="error-function">', $trace['function'], '</span>'; } } else { echo '<span class="error-function">', $trace['function'], '</span>'; } } if (isset($trace['args'])) { $arguments = array(); foreach ($trace['args'] as $argument) { if (is_scalar($argument)) { if (is_bool($argument)) { if ($argument) { $arguments[] = '<span class="error-parameter">true</span>'; } else { $arguments[] = '<span class="error-parameter">null</span>'; } continue; } if (is_string($argument)) { $argument = $this->_escapeString($argument); } $arguments[] = '<span class="error-parameter">' . $argument . '</span>'; } else { if (is_object($argument)) { if (method_exists($argument, 'dump')) { $arguments[] = '<span class="error-parameter">Object(' . get_class($argument) . ': ' . $this->_getArrayDump($argument->dump()) . ')</span>'; } else { $arguments[] = '<span class="error-parameter">Object(' . get_class($argument) . ')</span>'; } } else { if (is_array($argument)) { $arguments[] = '<span class="error-parameter">Array(' . $this->_getArrayDump($argument) . ')</span>'; } else { if (is_null($argument)) { $arguments[] = '<span class="error-parameter">null</span>'; continue; } } } } } echo '(' . join(', ', $arguments) . ')'; } if (isset($trace['file'])) { echo '<br/><span class="error-file">', $trace['file'], ' (', $trace['line'], ')</span>'; } echo '</td></tr>'; if ($this->_showFiles) { if (isset($trace['file'])) { echo '</table>'; $line = $trace['line']; $lines = file($trace['file']); if ($this->_showFileFragment) { $numberLines = count($lines); $firstLine = $line - 7 < 1 ? 1 : $line - 7; $lastLine = $line + 5 > $numberLines ? $numberLines : $line + 5; echo "<pre class='prettyprint highlight:" . $firstLine . ":" . $line . " linenums:" . $firstLine . "'>"; } else { $firstLine = 1; $lastLine = count($lines) - 1; echo "<pre class='prettyprint highlight:" . $firstLine . ":" . $line . " linenums error-scroll'>"; } for ($i = $firstLine; $i <= $lastLine; ++$i) { if ($this->_showFileFragment) { if ($i == $firstLine) { if (preg_match('#\\*\\/$#', rtrim($lines[$i - 1]))) { $lines[$i - 1] = str_replace("* /", " ", $lines[$i - 1]); } } } if ($lines[$i - 1] != PHP_EOL) { $lines[$i - 1] = str_replace("\t", " ", $lines[$i - 1]); echo htmlentities($lines[$i - 1], ENT_COMPAT, 'UTF-8'); } else { echo ' ' . "\n"; } } echo '</pre>'; echo '<table cellspacing="0">'; } } }
/** * Show reflection * * Show reflection * * <code> * Panda_Debug::reflect('BEAR_Form'); // Class * Panda_Debug::reflect($obj); // Objecy * Panda_Debug::reflect('p'); // Function * </code> * * @param string $target target * @param boll $cehckParent check parent class * * @return void */ public static function reflect($target, $cehckParent = false) { if (is_object($target)) { $target = get_class($target); } switch (true) { case function_exists($target): $ref = new ReflectionFunction($target); $info['name'] = $ref->isInternal() ? 'The internal ' : 'The user-defined '; $info['name'] .= $targetName = $ref->getName(); $info['declare in'] = $ref->getFileName() . ' lines ' . $ref->getStartLine() . ' to ' . $ref->getEndline(); $info['Documentation'] = $ref->getDocComment(); $statics = $ref->getStaticVariables(); if ($statics) { $info['Static variables'] = $statics; } $type = 'function'; break; case class_exists($target, false): $ref = new ReflectionClass($target); $type = 'class'; $info['name'] = $ref->isInternal() ? 'The internal ' : 'The user-defined '; $info['name'] .= $ref->isAbstract() ? ' abstract ' : ''; $info['name'] .= $ref->isFinal() ? ' final ' : ''; $info['name'] .= $ref->isInterface() ? 'interface ' : 'class '; $info['name'] .= $targetName = $ref->getName(); $info['declare in'] = $ref->getFileName() . ' lines ' . $ref->getStartLine() . ' to ' . $ref->getEndline(); $info['modifiers'] = Reflection::getModifierNames($ref->getModifiers()); $info['Documentation'] = $ref->getDocComment(); $info['Implements'] = $ref->getInterfaces(); $info['Constants'] = $ref->getConstants(); foreach ($ref->getProperties() as $prop) { // ReflectionProperty クラスのインスタンスを生成する $propRef = new ReflectionProperty($targetName, $prop->name); if ($propRef->isPublic()) { $porps[] = $prop->name; } } // $info['Public Properties'] = $porps; foreach ($ref->getMethods() as $method) { $methodRef = new ReflectionMethod($targetName, $method->name); if ($methodRef->isPublic() || $method->isStatic()) { $final = $method->isFinal() ? 'final ' : ''; $pubic = $method->isPublic() ? 'public ' : ''; $static = $method->isStatic() ? ' static ' : ''; $methods[] = sprintf("%s%s%s %s", $final, $pubic, $static, $method->name); } } $info['Public Methods'] = $methods; if ($ref->isInstantiable() && is_object($target)) { $info['isInstance ?'] = $ref->isInstance($target) ? 'yes' : 'no'; } if ($parent) { $info['parent'] .= $ref->getParentClass(); } break; default: $type = 'Invalid Object/Class'; $targetName = $target; $info = null; break; } print_a($info, "show_objects:1;label: Reflection of {$type} '{$targetName}'"); }
/** * getDebugBacktrace. * * Transforms the output of php's debug_backtrace() and exception backtraces * to a more readable html format. * * @return string $backtrace_string contains the backtrace */ public static function getDebugBacktrace($trace = null) { // show backtraces only in DEBUG mode if (defined('DEBUG') === false xor DEBUG === 0) { return; } // Normally backtraces are incomming from exceptions. // But, when called from the errorhandler, we need to fetch the traces ourselfs. if ($trace === null) { if (function_exists('xdebug_get_function_stack')) { $trace = xdebug_get_function_stack(); } else { $trace = debug_backtrace(); } /* * Now we get rid of several last calls in the backtrace stack, * to get nearer to the relevant error position in the stack. * * What exactly happens is: we shift-off the last 3 calls to * 1) getDebugBacktrace() [this method itself] * 2) yellowScreenOfDeath() [our exception and error display method] * 3) trigger_error() [php core function call] */ $trace = array_slice($trace, 3); } /* * Assemble the html for the backtrace panel */ $html = ''; $html .= '<div id="panel3" class="panel"><h3>Backtrace</h3>'; $html .= '<table class="cs-backtrace-table" width="95%">'; // table row 1 - header $html .= '<tr><th width="2%">Callstack</th><th>Function</th><th width="46%">Location</th></tr>'; // the number of backtraces $backtraces_counter_i = count($trace) - 1; for ($i = 0; $i <= $backtraces_counter_i; ++$i) { $html .= '<tr>'; // Position in the Callstack $html .= '<td align="center">' . ($backtraces_counter_i - $i + 1) . '</td>'; if (isset($trace[$i]['class']) === false) { $html .= '<td>[A PHP Core Function Call]</td>'; } else { // replace trace type string with it's operator if ($trace[$i]['type'] === 'dynamic') { $trace[$i]['type'] = '->'; } else { $trace[$i]['type'] = '::'; } $html .= '<td>'; // show the function call, e.g. Class->Method() or Class::Method() $html .= $trace[$i]['class'] . $trace[$i]['type'] . $trace[$i]['function'] . '()'; // if the class is one of our own, add backlink to API Documentation if (1 === preg_match('/^Koch/', $trace[$i]['class'])) { $html .= '<span class="error-class">'; $html .= '<a target="_new" href="http://docs.kf.com/en/latest/api/'; $html .= str_replace('\\', '_', $trace[$i]['class']); $html .= '.html"> ' . $trace[$i]['class'] . '</a></span>'; } else { // else it's a php internal class, then add a backlink to the php manual $classReflection = new \ReflectionClass($trace[$i]['class']); if ($classReflection->isInternal()) { $html .= '<span class="error-class"><a target="_new" href="http://php.net/manual/en/class.'; $html .= str_replace('_', '-', strtolower($trace[$i]['class'])); $html .= '.php">' . $trace[$i]['class'] . '</a></span>'; } else { $html .= '<span class="error-class">' . $trace[$i]['class'] . '</span>'; } } // is this a normal php function? if yes, add a backlink to the php manual if (function_exists($trace[$i]['function'])) { $functionReflection = new \ReflectionFunction($trace[$i]['function']); if ($functionReflection->isInternal()) { $html .= '<span class="error-function">'; $html .= '<a target="_new" href="http://php.net/manual/en/function.'; $html .= str_replace('_', '-', $trace[$i]['function']); $html .= '.php">' . $trace[$i]['function'] . '</a></span>'; } } // XDebug uses the array key 'params' for the method parameters array // PHP backtrace uses 'args', so let's rename to 'args' if (isset($trace[$i]['params'])) { $trace[$i]['args'] = $trace[$i]['params']; unset($trace[$i]['params']); } // Method Arguments if (isset($trace[$i]['args']) && empty($trace[$i]['args']) === false) { // the number of arguments (method parameters) $backtrace_counter_j = count($trace[$i]['args']) - 1; // use reflection to get the method parameters (and their names for display) $reflected_method = new \ReflectionMethod($trace[$i]['class'], $trace[$i]['function']); /* @var $reflected_params \ReflectionParameter */ $reflected_params = $reflected_method->getParameters(); // render a table with method parameters // argument position | name | type | value $html .= '<table style="border-collapse: collapse;">'; $html .= '<tr><th style="line-height: 0.8em;" colspan="4">Parameters</th></tr>'; $html .= '<tr style="line-height: 0.8em;">'; $html .= '<th>Pos</th><th>Name = Default Value</th><th>Type</th><th>Value</th></tr>'; // loop over all arguments for ($j = 0; $j <= $backtrace_counter_j; ++$j) { // fetch data for this argument $data = self::formatBacktraceArgument($trace[$i]['args'][$j]); // fetch current reflection parameter object $parameter = $reflected_params[$j]; // get just the parameter name and it's default value preg_match('/\\[ ([^[]+) \\]/', $parameter, $matches); $html .= '<tr>'; $html .= '<td>' . ($j + 1) . '</td>'; // pos $html .= '<td>' . $matches['1'] . '</td>'; // name $html .= '<td>' . $data['type'] . '</td>'; // type $html .= '<td>' . $data['arg'] . '</td>'; // value $defaultValue } $html .= '</tr></table>'; } $html .= '</td>'; } // Location with Link if (isset($trace[$i]['file'])) { $html .= '<td>' . self::getFileLink($trace[$i]['file'], $trace[$i]['line']) . '</td>'; } $html .= '</tr>'; } $html .= '</table></div>'; return $html; }
var_dump($rf->getName()); print "\n"; print "--- getNumberOfParameters(\"f\") ---\n"; var_dump($rf->getNumberOfParameters()); print "\n"; print "--- getNumberOfRequiredParameters(\"f\") ---\n"; var_dump($rf->getNumberOfRequiredParameters()); print "\n"; print "--- getParameters(\"f\") ---\n"; var_dump($rf->getParameters()); print "\n"; print "--- getStaticVariables(\"f\") ---\n"; var_dump($rf->getStaticVariables()); print "\n"; print "--- isInternal(\"f\") ---\n"; var_dump($rf->isInternal()); print "\n"; print "--- isUserDefined(\"f\") ---\n"; var_dump($rf->isUserDefined()); print "\n"; print "--- returnsReference(\"f\") ---\n"; var_dump($rf->returnsReference()); print "\n"; print "--- export(\"f\") ---\n"; var_dump($rf->export('f', true)); print "\n"; # invoke() can't be used because $b is pass-by-reference. print "--- invokeArgs(\"f\") ---\n"; $b = "b"; var_dump($rf->invokeArgs(array("a", &$b, "c"))); var_dump($rf->invokeArgs(array("a", &$b, "c")));
/** * Parse the loaded string into an array * Source is returned with the element key corresponding to the line number * * @access public * @param bool $funcref Reference functions to the PHP manual * @return array An array of highlighted source code */ function toArray($funcref = true) { // Ensure source has been loaded if ($this->_source == false) { return false; } // Init $tokens = token_get_all($this->_source); $manual = $this->manual; $span = $this->span; $i = 0; $out = array(); $out[$i] = ''; // Loop through each token foreach ($tokens as $j => $token) { // Single char if (is_string($token)) { // Skip token2color check for speed $out[$i] .= sprintf($span, $this->highlight['keyword'], htmlspecialchars($token)); // Heredocs behave strangely list($tb) = isset($tokens[$j - 1]) ? $tokens[$j - 1] : false; if ($tb == T_END_HEREDOC) { $out[++$i] = ''; } continue; } // Proper token list($token, $value) = $token; // Make the value safe $value = htmlspecialchars($value); $value = str_replace($this->replace[0], $this->replace[1], $value); // Process if ($value === "\n") { // End this line and start the next $out[++$i] = ''; } else { // Function linking if ($funcref === true && $token === T_STRING) { // Look ahead 1, look ahead 2, and look behind 3 if ((isset($tokens[$j + 1]) && $tokens[$j + 1] === '(' || isset($tokens[$j + 2]) && $tokens[$j + 2] === '(') && isset($tokens[$j - 3][0]) && $tokens[$j - 3][0] !== T_FUNCTION && function_exists($value)) { $funcion = new ReflectionFunction($value); // Insert the manual link if ($funcion->isInternal()) { $value = sprintf($manual, $value, $value); } } } // Explode token block $lines = explode("\n", $value); foreach ($lines as $jj => $line) { $line = trim($line); if ($line !== '') { $out[$i] .= sprintf($span, $this->_token2color($token), $line); } // Start a new line if (isset($lines[$jj + 1])) { $out[++$i] = ''; } } } } return $out; }
/** * Introspect a php callable and its phpdoc block and extract information about its signature * * @param callable $callable * @param string $plainFuncName * @return array|false */ protected function introspectFunction($callable, $plainFuncName) { // start to introspect PHP code if (is_array($callable)) { $func = new \ReflectionMethod($callable[0], $callable[1]); if ($func->isPrivate()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is private: ' . $plainFuncName); return false; } if ($func->isProtected()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is protected: ' . $plainFuncName); return false; } if ($func->isConstructor()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the constructor: ' . $plainFuncName); return false; } if ($func->isDestructor()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is the destructor: ' . $plainFuncName); return false; } if ($func->isAbstract()) { error_log('XML-RPC: ' . __METHOD__ . ': method to be wrapped is abstract: ' . $plainFuncName); return false; } /// @todo add more checks for static vs. nonstatic? } else { $func = new \ReflectionFunction($callable); } if ($func->isInternal()) { // Note: from PHP 5.1.0 onward, we will possibly be able to use invokeargs // instead of getparameters to fully reflect internal php functions ? error_log('XML-RPC: ' . __METHOD__ . ': function to be wrapped is internal: ' . $plainFuncName); return false; } // retrieve parameter names, types and description from javadoc comments // function description $desc = ''; // type of return val: by default 'any' $returns = Value::$xmlrpcValue; // desc of return val $returnsDocs = ''; // type + name of function parameters $paramDocs = array(); $docs = $func->getDocComment(); if ($docs != '') { $docs = explode("\n", $docs); $i = 0; foreach ($docs as $doc) { $doc = trim($doc, " \r\t/*"); if (strlen($doc) && strpos($doc, '@') !== 0 && !$i) { if ($desc) { $desc .= "\n"; } $desc .= $doc; } elseif (strpos($doc, '@param') === 0) { // syntax: @param type $name [desc] if (preg_match('/@param\\s+(\\S+)\\s+(\\$\\S+)\\s*(.+)?/', $doc, $matches)) { $name = strtolower(trim($matches[2])); //$paramDocs[$name]['name'] = trim($matches[2]); $paramDocs[$name]['doc'] = isset($matches[3]) ? $matches[3] : ''; $paramDocs[$name]['type'] = $matches[1]; } $i++; } elseif (strpos($doc, '@return') === 0) { // syntax: @return type [desc] if (preg_match('/@return\\s+(\\S+)(\\s+.+)?/', $doc, $matches)) { $returns = $matches[1]; if (isset($matches[2])) { $returnsDocs = trim($matches[2]); } } } } } // execute introspection of actual function prototype $params = array(); $i = 0; foreach ($func->getParameters() as $paramObj) { $params[$i] = array(); $params[$i]['name'] = '$' . $paramObj->getName(); $params[$i]['isoptional'] = $paramObj->isOptional(); $i++; } return array('desc' => $desc, 'docs' => $docs, 'params' => $params, 'paramDocs' => $paramDocs, 'returns' => $returns, 'returnsDocs' => $returnsDocs); }
/** * Shows a backtrace item * * @param int $n * @param array $trace * @return string * @throws Exception */ protected function showTraceItem($n, $trace) { /** * Every trace in the backtrace have a unique number */ $html = '<tr><td align="right" valign="top" class="error-number">#' . $n . '</td><td>'; if (isset($trace["class"])) { $className = $trace["class"]; /** * We assume that classes starting by Phalcon are framework's classes */ if (preg_match("/^Scene/", $className)) { /** * Prepare the class name according to the Phalcon's conventions */ $prepareUriClass = str_replace("\\", "/", $className); /** * Generate a link to the official docs */ $html .= '<span class="error-class"><a target="_new" href="//api.scene.ainstant.com/class/' . $prepareUriClass . '.html">' . $className . '</a></span>'; } else { $classReflection = new \ReflectionClass($className); /** * Check if classes are PHP's classes */ if ($classReflection->isInternal()) { $prepareInternalClass = str_replace("_", "-", strtolower($className)); /** * Generate a link to the official docs */ $html .= '<span class="error-class"><a target="_new" href="http://php.net/manual/en/class.' . $prepareInternalClass . '.php">' . $className . '</a></span>'; } else { $html .= '<span class="error-class">' . $className . '</span>'; } } /** * Object access operator: static/instance */ $html .= $trace['type']; } /** * Normally the backtrace contains only classes */ $functionName = $trace['function']; if (isset($trace['class'])) { $html .= '<span class="error-function">' . $functionName . '</span>'; } else { /** * Check if the function exists */ if (function_exists($functionName)) { $functionReflection = new \ReflectionFunction($functionName); /** * Internal functions links to the PHP documentation */ if ($functionReflection->isInternal()) { /** * Prepare function's name according to the conventions in the docs */ $preparedFunctionName = str_replace("_", "-", $functionName); $html .= '<span class="error-function"><a target="_new" href="http://php.net/manual/en/function.' . $preparedFunctionName . '.php">' . $functionName . '</a></span>'; } else { $html .= '<span class="error-function">' . $functionName . '</span>'; } } else { $html .= '<span class="error-function">' . $functionName . '</span>'; } } /** * Check for arguments in the function */ if (isset($trace['args'])) { $traceArgs = $trace['args']; if (count($traceArgs)) { $arguments = []; foreach ($traceArgs as $argument) { /** * Every argument is generated using _getVarDump * Append the HTML generated to the argument's list */ $arguments[] = '<span class="error-parameter">' . $this->_getVarDump($argument) . '</span>'; } /** * Join all the arguments */ $html .= '(' . join(', ', $arguments) . ')'; } else { $html .= '()'; } } /** * When "file" is present, it usually means the function is provided by the user */ if (isset($trace['file'])) { $filez = $trace['file']; $line = (string) $trace['line']; /** * Realpath to the file and its line using a special header */ $html .= '<br/><div class="error-file">' . $filez . ' (' . $line . ')</div>'; $showFiles = $this->_showFiles; if ($showFiles) { /** * Open the file to an array using "file", this respects the openbase-dir directive */ $lines = file($filez); $numberLines = count($lines); $showFileFragment = $this->_showFileFragment; /** * File fragments just show a piece of the file where the exception is located */ if ($showFileFragment) { /** * Take seven lines back to the current exception's line, @TODO add an option for this */ $beforeLine = $line - 7; /** * Check for overflows */ if ($beforeLine < 1) { $firstLine = 1; } else { $firstLine = $beforeLine; } /** * Take five lines after the current exception's line, @TODO add an option for this */ $afterLine = $line + 5; /** * Check for overflows */ if ($afterLine > $numberLines) { $lastLine = $numberLines; } else { $lastLine = $afterLine; } $html .= '<pre class="prettyprint highlight:' . $firstLine . ':' . $line . " linenums:" . $firstLine . '">'; } else { $firstLine = 1; $lastLine = $numberLines; $html .= '<pre class="prettyprint highlight:' . $firstLine . ':' . $line . ' linenums error-scroll">'; } $i = $firstLine; while ($i <= $lastLine) { /** * Current line in the file */ $linePosition = $i - 1; /** * Current line content in the piece of file */ $currentLine = $lines[$linePosition]; /** * File fragments are cleaned, removing tabs and comments */ if ($showFileFragment) { if ($i == $firstLine) { if (preg_match("#\\*\\/#", rtrim($currentLine))) { $currentLine = str_replace("* /", " ", $currentLine); } } } /** * Print a non break space if the current line is a line break, this allows to show the html zebra properly */ if ($currentLine == "\n" || $currentLine == "\r\n") { $html .= " \n"; } else { /** * Don't escape quotes * We assume the file is utf-8 encoded, @TODO add an option for this */ $html .= htmlentities(str_replace("\t", " ", $currentLine), ENT_COMPAT, "UTF-8"); } $i++; } $html .= '</pre>'; } } $html .= '</td></tr>'; return $html; }