Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/main/classes/general/ |
Upload File : |
<?php /** * Bitrix Framework * @package bitrix * @subpackage main * @copyright 2001-2025 Bitrix */ class PHPParser { protected static $arAllStr; public static function ReplString($str, $arAllStr) { self::$arAllStr = $arAllStr; if (preg_match("'^\x01([0-9]+)\x02$'s", $str)) { return preg_replace_callback("'\x01([0-9]+)\x02's", "PHPParser::getString", $str); } if (strval(floatval($str)) == $str) { return preg_replace_callback("'\x01([0-9]+)\x02's", "PHPParser::getQuotedString", $str); } elseif ($str == "") { return ""; } else { return "={" . preg_replace_callback("'\x01([0-9]+)\x02's", "PHPParser::getQuotedString", $str) . "}"; } } public static function getString($matches) { return self::$arAllStr[$matches[1]]; } public static function getQuotedString($matches) { return '"' . self::$arAllStr[$matches[1]] . '"'; } public static function GetParams($params) { $arParams = []; $brackets = 0; $param_tmp = ""; $params_l = mb_strlen($params); for ($i = 0; $i < $params_l; $i++) { $ch = mb_substr($params, $i, 1); if ($ch == "(" || $ch == "[") { $brackets++; } elseif ($ch == ")" || $ch == "]") { $brackets--; } elseif ($ch == "," && $brackets == 0) { $arParams[] = $param_tmp; $param_tmp = ""; continue; } if ($brackets < 0) { break; } $param_tmp .= $ch; } if ($param_tmp <> "") { $arParams[] = $param_tmp; } return $arParams; } public static function GetParamsRec($params, &$arAllStr, &$arResult) { $found = false; $paramsList = ""; if (strtolower(substr($params, 0, 6)) == 'array(') { $found = true; $paramsList = substr($params, 6); } elseif (str_starts_with($params, "[")) { $found = true; $paramsList = substr($params, 1); } if ($found) { $arParams = static::GetParams($paramsList); foreach ($arParams as $i => $el) { if (strtolower(substr($el, 0, 6)) == 'array(' || str_starts_with($el, '[')) { // no index, value is an array. We should check it first, because this array can contain '=>' operator. $p = false; } else { // possible index $p = mb_strpos($el, "=>"); } if ($p === false) { // value without index if (is_string($arResult)) { $arResult = static::ReplString($el, $arAllStr); } else { static::GetParamsRec($el, $arAllStr, $arResult[$i]); } } else { // value with index $el_ind = static::ReplString(mb_substr($el, 0, $p), $arAllStr); $el_val = mb_substr($el, $p + 2); static::GetParamsRec($el_val, $arAllStr, $arResult[$el_ind]); } } } else { $arResult = static::ReplString($params, $arAllStr); } } // Parse string and check if it is a component call. Return call params array public static function CheckForComponent($str) { if (str_starts_with($str, "<?php")) { $str = substr($str, 5); } else { $str = substr($str, 2); } $str = substr($str, 0, -2); $bSlashed = false; $bInString = false; $arAllStr = []; $new_str = ""; $string_tmp = ""; $quote_ch = ""; $i = -1; $length = mb_strlen($str); while ($i < $length - 1) { $i++; $ch = mb_substr($str, $i, 1); if (!$bInString) { if ($string_tmp != "") { $arAllStr[] = $string_tmp; $string_tmp = ""; $new_str .= chr(1) . (count($arAllStr) - 1) . chr(2); } //comment if ($ch == "/" && $i + 1 < $length) { $ti = 0; if (mb_substr($str, $i + 1, 1) == "*" && ($ti = mb_strpos($str, "*/", $i + 2)) !== false) { $ti += 2; } elseif (mb_substr($str, $i + 1, 1) == "/" && ($ti = mb_strpos($str, "\n", $i + 2)) !== false) { $ti += 1; } if ($ti) { $i = $ti; } continue; } if ($ch == " " || $ch == "\r" || $ch == "\n" || $ch == "\t") { continue; } } if ($bInString && $ch == "\\" && !$bSlashed) { $bSlashed = true; continue; } if ($ch == "\"" || $ch == "'") { if ($bInString) { if (!$bSlashed && $quote_ch == $ch) { $bInString = false; continue; } } else { $bInString = true; $quote_ch = $ch; continue; } } $bSlashed = false; if ($bInString) { $string_tmp .= $ch; continue; } $new_str .= $ch; } if ($pos = mb_strpos($new_str, "(")) { $func_name = mb_substr($new_str, 0, $pos + 1); if (preg_match("/^(\\\$[A-Z_][A-Z0-9_]*)(\\s*=\\s*)/i", $func_name, $arMatch)) { $var_name = $arMatch[1]; $func_name = mb_substr($func_name, mb_strlen($arMatch[0])); } else { $var_name = ""; } $func_name = preg_replace("'\\\$GLOBALS\\[(\"|\\')(.+?)(\"|\\')\\]'s", "\$\\2", $func_name); switch (mb_strtoupper($func_name)) { case '$APPLICATION->INCLUDEFILE(': $params = mb_substr($new_str, $pos + 1); $arParams = static::GetParams($params); $arIncludeParams = []; if (preg_match("/^array\\(/i", $arParams[1])) { $arParams2 = static::GetParams(mb_substr($arParams[1], 6)); foreach ($arParams2 as $el) { $p = mb_strpos($el, "=>"); $el_ind = static::ReplString(mb_substr($el, 0, $p), $arAllStr); $el_val = mb_substr($el, $p + 2); if (preg_match("/^array\\(/i", $el_val)) { $res_ar = []; $arParamsN = static::GetParams(mb_substr($el_val, 6)); foreach ($arParamsN as $param) { $res_ar[] = static::ReplString($param, $arAllStr); } $arIncludeParams[$el_ind] = $res_ar; } else { $arIncludeParams[$el_ind] = static::ReplString($el_val, $arAllStr); } } } return [ "SCRIPT_NAME" => static::ReplString($arParams[0], $arAllStr), "PARAMS" => $arIncludeParams, "VARIABLE" => $var_name, ]; } } return false; } public static function GetComponentParams($instruction, $arAllStr) { if ($pos = mb_strpos($instruction, "(")) { $func_name = mb_substr($instruction, 0, $pos + 1); if (preg_match("/(\\\$[A-Z_][A-Z0-9_]*)(\\s*=\\s*)/i", $func_name, $arMatch)) { $var_name = $arMatch[1]; } else { $var_name = ""; } $params = mb_substr($instruction, $pos + 1); $arParams = static::GetParams($params); $arIncludeParams = []; $arFuncParams = []; if (!empty($arParams[2])) { static::GetParamsRec($arParams[2], $arAllStr, $arIncludeParams); } if (!empty($arParams[4])) { static::GetParamsRec($arParams[4], $arAllStr, $arFuncParams); } return [ "COMPONENT_NAME" => static::ReplString($arParams[0] ?? '', $arAllStr), "TEMPLATE_NAME" => static::ReplString($arParams[1] ?? '', $arAllStr), "PARAMS" => $arIncludeParams, "PARENT_COMP" => $arParams[3] ?? '', "VARIABLE" => $var_name, "FUNCTION_PARAMS" => $arFuncParams, "RETURN_RESULT" => $arParams[5] ?? '', ]; } return []; } public static function ParseScript($scriptContent) { $arComponents = []; $componentNumber = -1; $bInComponent = false; $bInPHP = false; $bInString = false; $quoteChar = ""; $bSlashed = false; $string = false; $instruction = ""; //mb_substr is catastrophic slow, so in UTF we use array of characters $allChars = preg_split('//u', $scriptContent, -1, PREG_SPLIT_NO_EMPTY); if ($allChars === false) { return []; } $scriptContentLength = mb_strlen($scriptContent); $arAllStr = []; $ind = -1; while ($ind < $scriptContentLength - 1) { $ind++; $ch = $allChars[$ind]; if ($bInPHP) { if (!$bInString) { if (!$bInComponent && $instruction <> '') { if (preg_match("#\\s*((\\\$[A-Z_][A-Z0-9_]*\\s*=)?\\s*\\\$APPLICATION->IncludeComponent\\s*\\()#is", $instruction, $arMatches)) { $arAllStr = []; $bInComponent = true; $componentNumber++; $instruction = $arMatches[1]; $arComponents[$componentNumber] = [ "START" => ($ind - mb_strlen($arMatches[1])), "END" => false, "DATA" => [], ]; } } if ($string !== false) { if ($bInComponent) { $arAllStr[] = $string; $instruction .= chr(1) . (count($arAllStr) - 1) . chr(2); } $string = false; } if ($ch == ";") { if ($bInComponent) { $bInComponent = false; $arComponents[$componentNumber]["END"] = $ind + 1; $arComponents[$componentNumber]["DATA"] = static::GetComponentParams(preg_replace("#[ \r\n\t]#", "", $instruction), $arAllStr); } $instruction = ""; continue; } if ($ch == "/" && $ind < $scriptContentLength - 2) { $nextChar = $allChars[$ind + 1]; if ($nextChar == "/") { $endPos = mb_strpos($scriptContent, "\n", $ind + 2); if ($endPos === false) { $ind = $scriptContentLength - 1; } else { $ind = $endPos; } continue; } elseif ($nextChar == "*") { $endPos = mb_strpos($scriptContent, "*/", $ind + 2); if ($endPos === false) { $ind = $scriptContentLength - 1; } else { $ind = $endPos + 1; } continue; } } if ($ch == "\"" || $ch == "'") { $bInString = true; $string = ""; $quoteChar = $ch; continue; } if ($ch == "?" && $ind < $scriptContentLength - 2 && $allChars[$ind + 1] == ">") { $ind += 1; if ($bInComponent) { $bInComponent = false; $arComponents[$componentNumber]["END"] = $ind - 1; $arComponents[$componentNumber]["DATA"] = static::GetComponentParams(preg_replace("#[ \r\n\t]#", "", $instruction), $arAllStr); } $instruction = ""; $bInPHP = false; continue; } $instruction .= $ch; if ($ch == " " || $ch == "\r" || $ch == "\n" || $ch == "\t") { continue; } } else { if ($ch == "\\" && !$bSlashed) { $bSlashed = true; continue; } if ($ch == $quoteChar && !$bSlashed) { $bInString = false; continue; } $bSlashed = false; $string .= $ch; } } else { if ($ch == "<") { if ($ind < $scriptContentLength - 5 && $allChars[$ind + 1] . $allChars[$ind + 2] . $allChars[$ind + 3] . $allChars[$ind + 4] == "?php") { $bInPHP = true; $ind += 4; } elseif ($ind < $scriptContentLength - 2 && $allChars[$ind + 1] == "?") { $bInPHP = true; $ind += 1; } } } } return $arComponents; } // Components 2. Parse string and check if it is a component call. Return call params array public static function CheckForComponent2($str) { if (str_starts_with($str, "<?php")) { $str = substr($str, 5); } else { $str = substr($str, 2); } $str = substr($str, 0, -2); $bSlashed = false; $bInString = false; $arAllStr = []; $new_str = ""; $string_tmp = ""; $quote_ch = ""; $i = -1; $length = mb_strlen($str); while ($i < $length - 1) { $i++; $ch = mb_substr($str, $i, 1); if (!$bInString) { if ($string_tmp != "") { $arAllStr[] = $string_tmp; $string_tmp = ""; $new_str .= chr(1) . (count($arAllStr) - 1) . chr(2); } //comment if ($ch == "/" && $i + 1 < $length) { $ti = 0; if (mb_substr($str, $i + 1, 1) == "*" && ($ti = mb_strpos($str, "*/", $i + 2)) !== false) { $ti += 1; } elseif (mb_substr($str, $i + 1, 1) == "/" && ($ti = mb_strpos($str, "\n", $i + 2)) !== false) { $ti += 0; } if ($ti) { $i = $ti; } continue; } if ($ch == " " || $ch == "\r" || $ch == "\n" || $ch == "\t") { continue; } } if ($bInString && $ch == "\\" && !$bSlashed) { $bSlashed = true; continue; } if ($ch == "\"" || $ch == "'") { if ($bInString) { if (!$bSlashed && $quote_ch == $ch) { $bInString = false; continue; } } else { $bInString = true; $quote_ch = $ch; continue; } } $bSlashed = false; if ($bInString) { $string_tmp .= $ch; continue; } $new_str .= $ch; } if ($pos = mb_strpos($new_str, "(")) { $func_name = mb_substr($new_str, 0, $pos + 1); if (preg_match("/^(\\\$[A-Z_][A-Z0-9_]*)(\\s*=\\s*)/i", $func_name, $arMatch)) { $var_name = $arMatch[1]; $func_name = mb_substr($func_name, mb_strlen($arMatch[0])); } else { $var_name = ""; } self::$arAllStr = $arAllStr; $func_name = preg_replace_callback("'\x01([0-9]+)\x02's", "PHPParser::getString", $func_name); $isComponent2Begin = false; $arIncludeComponentFunctionStrings = self::getComponentFunctionStrings(); foreach ($arIncludeComponentFunctionStrings as $functionName) { $component2Begin = mb_strtoupper($functionName) . '('; if (mb_strtoupper($func_name) == $component2Begin) { $isComponent2Begin = true; break; } } if ($isComponent2Begin) { $params = mb_substr($new_str, $pos + 1); $arParams = static::GetParams($params); $arIncludeParams = []; $arFuncParams = []; static::GetParamsRec($arParams[2], $arAllStr, $arIncludeParams); static::GetParamsRec($arParams[4], $arAllStr, $arFuncParams); return [ "COMPONENT_NAME" => static::ReplString($arParams[0], $arAllStr), "TEMPLATE_NAME" => static::ReplString($arParams[1], $arAllStr), "PARAMS" => $arIncludeParams, "PARENT_COMP" => $arParams[3], "VARIABLE" => $var_name, "FUNCTION_PARAMS" => $arFuncParams, ]; } } return false; } // Parse file and return all PHP blocks in array public static function ParseFile($filesrc, $limit = false) { $arScripts = []; $p = 0; $nLen = mb_strlen($filesrc); while (($p = mb_strpos($filesrc, "<?", $p)) !== false) { $i = $p + 2; $bSlashed = false; $bInString = false; $quote_ch = ""; while ($i < $nLen - 1) { $i++; $ch = mb_substr($filesrc, $i, 1); if (!$bInString) { //comment if ($ch == "/" && $i + 1 < $nLen) { //php tag $posnext = mb_strpos($filesrc, "?>", $i); if ($posnext === false) { //no final tag break; } $posnext += 2; $ti = 0; if (mb_substr($filesrc, $i + 1, 1) == "*" && ($ti = mb_strpos($filesrc, "*/", $i + 2)) !== false) { $ti += 2; } elseif (mb_substr($filesrc, $i + 1, 1) == "/" && ($ti = mb_strpos($filesrc, "\n", $i + 2)) !== false) { $ti += 1; } if ($ti) { // begin ($i) and end ($ti) of comment // проверим что раньше конец скрипта или конец комментария (например в одной строке "//comment ? >") if ($ti > $posnext && mb_substr($filesrc, $i + 1, 1) != "*") { // скрипт закончился раньше комментария // вырежем скрипт $arScripts[] = [$p, $posnext, mb_substr($filesrc, $p, $posnext - $p)]; break; } else { // комментарий закончился раньше скрипта $i = $ti - 1; } } continue; } if ($ch == "?" && $i + 1 < $nLen && mb_substr($filesrc, $i + 1, 1) == ">") { $i = $i + 2; $arScripts[] = [$p, $i, mb_substr($filesrc, $p, $i - $p)]; break; } } if ($bInString && $ch == "\\" && !$bSlashed) { $bSlashed = true; continue; } if ($ch == "\"" || $ch == "'") { if ($bInString) { if (!$bSlashed && $quote_ch == $ch) { $bInString = false; } } else { $bInString = true; $quote_ch = $ch; } } $bSlashed = false; } if ($i >= $nLen) { break; } if ($limit && count($arScripts) == $limit) { break; } $p = $i; } return $arScripts; } public static function PreparePHP($str) { if (str_starts_with($str, "={") && str_ends_with($str, "}") && mb_strlen($str) > 3) { return substr($str, 2, -1); } return '"' . EscapePHPString($str) . '"'; } // Return PHP string of component call params public static function ReturnPHPStr($arVals, $arParams) { $res = ""; $un = md5(uniqid()); $i = 0; foreach ($arVals as $key => $val) { $i++; $comm = ($arParams[$key]["NAME"] <> '' ? "$un|$i|// " . $arParams[$key]["NAME"] : ""); $res .= "\r\n\t\"" . $key . "\"\t=>\t"; if (is_array($val) && count($val) > 1) { $res .= "array(" . $comm . "\r\n"; } if (is_array($val) && count($val) > 1) { $zn = ''; foreach ($val as $p) { if ($zn != '') { $zn .= ",\r\n"; } $zn .= "\t\t\t\t\t" . static::PreparePHP($p); } $res .= $zn . "\r\n\t\t\t\t),"; } elseif (is_array($val)) { $res .= "array(" . static::PreparePHP($val[0]) . ")," . $comm; } else { $res .= static::PreparePHP($val) . "," . $comm; } } $max = 0; $lngth = []; for ($j = 1; $j <= $i; $j++) { $p = mb_strpos($res, "$un|$j|"); $pn = mb_strrpos(mb_substr($res, 0, $p), "\n"); $l = ($p - $pn); $lngth[$j] = $l; if ($max < $l) { $max = $l; } } for ($j = 1; $j <= $i; $j++) { $res = str_replace($un . "|$j|", str_repeat("\t", intval(($max - $lngth[$j] + 7) / 8)), $res); } return trim($res, " \t,\r\n"); } public static function ReturnPHPStrRec($arVal, $level, $comm = "") { $result = ""; $pref = str_repeat("\t", $level + 1); if (is_array($arVal)) { $result .= "[" . (($level == 1) ? $comm : "") . "\n"; foreach ($arVal as $key => $value) { $result .= $pref . "\t" . ((intval($key) . "|" == $key . "|") ? $key : static::PreparePHP($key)) . " => " . static::ReturnPHPStrRec($value, $level + 1); } $result .= $pref . "],\n"; } else { $result .= static::PreparePHP($arVal) . "," . (($level == 1) ? $comm : "") . "\n"; } return $result; } // Components 2. Return PHP string of component call params public static function ReturnPHPStr2($arVals, $arParams = []) { $res = ""; foreach ($arVals as $key => $val) { $res .= "\t\t\"" . EscapePHPString($key) . "\" => "; $comm = (!empty($arParams[$key]["NAME"]) ? "\t// " . $arParams[$key]["NAME"] : ""); $res .= static::ReturnPHPStrRec($val, 1, $comm); } return trim($res, " \t,\r\n"); } public static function FindComponent($component_name, $filesrc, $src_line) { /* parse source file for PHP code */ $arComponents = static::ParseScript($filesrc); /* identify the component by line number */ $arComponent = false; for ($i = 0, $cnt = count($arComponents); $i < $cnt; $i++) { $nLineFrom = substr_count(mb_substr($filesrc, 0, $arComponents[$i]["START"]), "\n") + 1; $nLineTo = substr_count(mb_substr($filesrc, 0, $arComponents[$i]["END"]), "\n") + 1; if ($nLineFrom <= $src_line && $nLineTo >= $src_line) { if ($arComponents[$i]["DATA"]["COMPONENT_NAME"] == $component_name) { $arComponent = $arComponents[$i]; break; } } if ($nLineTo > $src_line) { break; } } return $arComponent; } public static function getPhpChunks($filesrc, $limit = false) { $chunks = []; $chunk = ''; $php = false; if (function_exists("token_get_all")) { foreach (token_get_all($filesrc) as $token) { if ($php) { if (is_array($token)) { $chunk .= $token[1]; if ($token[0] === T_CLOSE_TAG) { $chunks[] = $chunk; $chunk = ''; $php = false; if ($limit && count($chunks) == $limit) { break; } } } else { $chunk .= $token; } } else { if (is_array($token)) { if ($token[0] === T_OPEN_TAG || $token[0] === T_OPEN_TAG_WITH_ECHO) { $chunk .= $token[1]; $php = true; } } } } } else { foreach (static::ParseFile($filesrc, $limit) as $chunk) { $chunks[] = $chunk[2]; } } if ($php && $chunk != '') { $chunks[] = $chunk; } return $chunks; } public static function getPageTitle($filesrc, $prolog = false) { if ($prolog === false) { $chunks = static::getPhpChunks($filesrc, 1); if (!empty($chunks)) { $prolog = &$chunks[0]; } else { $prolog = ''; } } $title = false; if ($prolog != '') { if (preg_match("/\\\$APPLICATION->SetTitle\\s*\\(\\s*\"(.*?)(?<!\\\\)\"\\s*\\);/is", $prolog, $regs)) { $title = UnEscapePHPString($regs[1]); } elseif (preg_match("/\\\$APPLICATION->SetTitle\\s*\\(\\s*'(.*?)(?<!\\\\)'\\s*\\);/is", $prolog, $regs)) { $title = UnEscapePHPString($regs[1]); } elseif (preg_match("'<title[^>]*>([^>]+)</title[^>]*>'i", $prolog, $regs)) { $title = $regs[1]; } } if (!$title && preg_match("'<title[^>]*>([^>]+)</title[^>]*>'i", $filesrc, $regs)) { $title = $regs[1]; } return $title; } public static function getComponentFunctionStrings() { return [ '$APPLICATION->IncludeComponent', 'EventMessageThemeCompiler::includeComponent', ]; } public static function buildComponentCode(array $component, ?string $templateName = null, ?array $parameters = null): string { if ($templateName === null) { $templateName = $component['DATA']['TEMPLATE_NAME']; } if ($parameters === null) { $parameters = $component['DATA']['PARAMS']; } $functionParams = ''; if (!empty($component['DATA']['FUNCTION_PARAMS'])) { $functionParams = ",\n" . "\t[\n" . "\t\t" . static::ReturnPHPStr2($component['DATA']['FUNCTION_PARAMS']) . "\n" . "\t]"; } elseif (!empty($component['DATA']['RETURN_RESULT'])) { $functionParams = ",\n\t[]"; } $code = ($component['DATA']['VARIABLE'] ? $component['DATA']['VARIABLE'] . ' = ' : '') . "\$APPLICATION->IncludeComponent(\n" . "\t\"" . $component['DATA']['COMPONENT_NAME'] . "\", \n" . "\t\"" . $templateName . "\", \n" . "\t[\n" . "\t\t" . static::ReturnPHPStr2($parameters) . "\n" . "\t],\n" . "\t" . (!empty($component['DATA']['PARENT_COMP']) ? $component['DATA']['PARENT_COMP'] : 'false') . $functionParams . (!empty($component['DATA']['RETURN_RESULT']) ? ",\n\t" . $component['DATA']['RETURN_RESULT'] : '') . "\n);"; return $code; } }