public static function errorHandler($errorLevel, $errorDesc, $filePath, $line) { // If any error processing is enabled, this function is called by the PHP runtime on a failed assertion or // runtime error. settype($errorLevel, "int"); settype($line, "int"); $reportThisError = true; if (CConfiguration::isInitialized()) { $errorReportingLevel = constant(CConfiguration::option("debug.errorReportingLevel")); if ($errorLevel & $errorReportingLevel == 0) { $reportThisError = false; } } if ($reportThisError) { // Avoid double reporting of the same error if the method registered with `register_shutdown_function` is // called by the runtime after an error occurred. $errorFileAndLine = []; $errorFileAndLine["file"] = $filePath; $errorFileAndLine["line"] = $line; self::$ms_processedErrors[] = $errorFileAndLine; $strErrorLevel; switch ($errorLevel) { case E_ERROR: // 1 $strErrorLevel = "E_ERROR"; break; case E_WARNING: // 2 $strErrorLevel = "E_WARNING"; break; case E_PARSE: // 4 $strErrorLevel = "E_PARSE"; break; case E_NOTICE: // 8 $strErrorLevel = "E_NOTICE"; break; case E_CORE_ERROR: // 16 $strErrorLevel = "E_CORE_ERROR"; break; case E_CORE_WARNING: // 32 $strErrorLevel = "E_CORE_WARNING"; break; case E_COMPILE_ERROR: // 64 $strErrorLevel = "E_COMPILE_ERROR"; break; case E_COMPILE_WARNING: // 128 $strErrorLevel = "E_COMPILE_WARNING"; break; case E_USER_ERROR: // 256 $strErrorLevel = "E_USER_ERROR"; break; case E_USER_WARNING: // 512 $strErrorLevel = "E_USER_WARNING"; break; case E_USER_NOTICE: // 1024 $strErrorLevel = "E_USER_NOTICE"; break; case E_STRICT: // 2048 $strErrorLevel = "E_STRICT"; break; case E_RECOVERABLE_ERROR: // 4096 $strErrorLevel = "E_RECOVERABLE_ERROR"; break; case E_DEPRECATED: // 8192 $strErrorLevel = "E_DEPRECATED"; break; case E_USER_DEPRECATED: // 16384 $strErrorLevel = "E_USER_DEPRECATED"; break; default: $strErrorLevel = (string) $errorLevel; break; } $time = gmdate(self::$ms_logRecordDateTimePattern, time()); $fileRelPath = str_replace(realpath($GLOBALS["PHRED_PATH_TO_FRAMEWORK_ROOT"]) . "/", "", $filePath); $isAssertWithVars = is_int(strpos($errorDesc, self::$ms_assertVarsMarker)); $errorDesc = preg_replace("/\\n{2,}/", "\n", $errorDesc); if (!$isAssertWithVars) { // In case of an assert without vars. $errorDesc = preg_replace("/^assert\\(\\)\\s*:\\s*/", "", $errorDesc); } else { $errorDesc = preg_replace("/^[^\\n]*\\n(.*)" . self::$ms_assertVarsMarker . "\\s*:\\s*([\"'][^\\n]*)\\s*\\z/s", "\$2 ({$strErrorLevel})\n\$1", $errorDesc); if (preg_match("/^\\s*assert/i", $errorDesc) !== 1) { $errorDesc = "Assertion {$errorDesc}"; } } // Backtrace. ob_start(); debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $backtrace = ob_get_clean(); $backtrace = preg_replace("/\\n{2,}/", "\n", $backtrace); $backtrace = preg_replace("/^\\s*#.*?(?=#)/s", "", $backtrace); // remove the first line that is useless $backtrace = str_replace(realpath($GLOBALS["PHRED_PATH_TO_FRAMEWORK_ROOT"]) . "/", "", $backtrace); $backtrace = preg_replace("/\\s+\\z/", "", $backtrace); // Format the error message. if (!$isAssertWithVars) { $errorMessage = "[Time:] {$time}\n\n[Location:] {$fileRelPath}, line {$line}\n\n{$errorDesc} ({$strErrorLevel})\n\n" . "[Backtrace:]\n{$backtrace}\n"; } else { $errorMessage = "[Time:] {$time}\n\n[Location:] {$fileRelPath}, line {$line}\n\n{$errorDesc}\n\n" . "[Backtrace:]\n{$backtrace}\n"; } $logRecordSep = rtrim(str_repeat("- ", 60)); $leSep = "\n\n{$logRecordSep}\n\n"; if (self::$ms_logging) { // Log the record. $logRecord = "{$errorMessage}\n{$logRecordSep}\n\n"; if (file_exists(self::$ms_errorLogFp)) { // Check if log rotation needs to be performed for the error log. $log = file_get_contents(self::$ms_errorLogFp); $numRecords = substr_count($log, $leSep); if ($numRecords >= self::$ms_maxNumRecordsInLog) { $numDelFirstRecords = $numRecords - self::$ms_maxNumRecordsInLog + 1; $pos; for ($i = 0; $i < $numDelFirstRecords; $i++) { $pos = !isset($pos) ? 0 : $pos + 1; $pos = strpos($log, $leSep, $pos); } $log = substr($log, $pos); $log = "\n{$logRecordSep}\n\n" . preg_replace("/^{$leSep}/", "", $log); file_put_contents(self::$ms_errorLogFp, $log); } } else { file_put_contents(self::$ms_errorLogFp, "\n{$logRecordSep}\n\n"); } file_put_contents(self::$ms_errorLogFp, $logRecord, FILE_APPEND); } if (self::$ms_mailing) { $doMail = true; $destDp = sys_get_temp_dir(); $docRoot = isset($_SERVER["DOCUMENT_ROOT"]) ? $_SERVER["DOCUMENT_ROOT"] : ""; $docRootHash = hash("crc32", $docRoot, false); $lastMailTimeFp = $destDp . "/" . self::$ms_lastMailingTimeFnPrefix . $docRootHash; if (file_exists($lastMailTimeFp)) { $lastMailTime = (int) file_get_contents($lastMailTimeFp); $lastMailTimeDiffSeconds = time() - $lastMailTime; // If the difference is negative, which is wrong, the mailing should not be canceled. if ($lastMailTimeDiffSeconds >= 0) { if ($lastMailTimeDiffSeconds < self::$ms_minTimeBetweenSendMailHours * 3600) { // Too little time has passed since the last mailing, so cancel this one. $doMail = false; } } } if ($doMail) { // Notify about the error by mail. // Format the subject. $subject = "Something curious was encountered on "; // alternative: "" $serverName = isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"] : ""; $serverIp = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : ""; $docRoot = isset($_SERVER["DOCUMENT_ROOT"]) ? basename($_SERVER["DOCUMENT_ROOT"]) : ""; if ($serverName !== "") { $subject .= $serverName; if ($serverIp !== "") { $subject .= " ({$serverIp})"; } if ($docRoot !== "") { $subject .= " in "; } else { $subject .= ""; // alternative: ": " } } if ($docRoot !== "") { $subject .= "'{$docRoot}'"; // alternative: "'$docRoot': " } // Alternative: // $subject .= "PHP Encountered a Problem"; // Compose the message. $mailMessage = "{$subject}\n\n{$errorMessage}"; if (self::$ms_logging && file_exists(self::$ms_errorLogFp)) { // Add the latest log records to the message. $log = file_get_contents(self::$ms_errorLogFp); $log .= "\n"; // to be able to use `-1` in `strrpos` below $logLength = strlen($log); $res = strrpos($log, $leSep, -1); if (is_int($res)) { for ($i = 0; $i < self::$ms_maxNumLatestLogRecordsInMailMessage; $i++) { $res = strrpos($log, $leSep, $res - $logLength - 1); if (!is_int($res)) { break; } } if (!is_int($res)) { $res = 0; } $latestRecords = substr($log, $res); $latestRecords = trim($latestRecords); $mailMessage .= "\n\n\n\n[Latest error log records, chronologically:]\n\n{$latestRecords}\n"; } } // Send. self::$ms_mail->setSubject($subject); self::$ms_mail->setBody($mailMessage); self::$ms_mail->disableWordWrapping(); $numMailsSent = self::$ms_mail->send(); if ($numMailsSent > 0) { file_put_contents($lastMailTimeFp, time()); } } } } // If a value other than `false` was returned, the error would not be shown in the output, regardless of // whether or not the PHP's "display_errors" option was enabled or disabled. return false; }
/** * @ignore */ public static function onThirdPartyUpdateByPackageManager() { if (!self::isInCliMode()) { // This method can be run in CLI mode only. assert('false', vs(isset($this), get_defined_vars())); } $timeoutPause = new CTimeoutPause(); CShell::speak("Processing third-party components ..."); $tpDps = CFile::listDirectories(CFilePath::absolute($GLOBALS["PHRED_PATH_TO_THIRD_PARTY"])); $ignorePackages = CConfiguration::option("upd.thirdPartyOopWrappingIgnorePackages"); $ignorePackagesL2 = CArray::filter($ignorePackages, function ($package) { return CString::find($package, "/"); }); $newTpDps = CArray::make(); $len = CArray::length($tpDps); for ($i = 0; $i < $len; $i++) { $tpDp = $tpDps[$i]; $dirName = CFilePath::name($tpDp); if (!CArray::find($ignorePackages, $dirName)) { $dpHasL2DirsToIgnore = CArray::find($ignorePackagesL2, $dirName, function ($packageL2, $dirName) { return CString::equals(CFilePath::directory($packageL2), $dirName); }); if (!$dpHasL2DirsToIgnore) { CArray::push($newTpDps, $tpDp); } else { $tpSubDps = CFile::listDirectories($tpDp); $tpSubDps = CArray::filter($tpSubDps, function ($subDp) use($ignorePackagesL2) { return !CArray::find($ignorePackagesL2, $subDp, function ($packageL2, $subDp) { return CString::endsWith($subDp, $packageL2); }); }); CArray::pushArray($newTpDps, $tpSubDps); } } } $tpDps = $newTpDps; $wrapProtectedMethods = CConfiguration::option("upd.thirdPartyOopWrappingInProtectedMethods"); $wrapPrivateMethods = CConfiguration::option("upd.thirdPartyOopWrappingInPrivateMethods"); static $s_stdPhpTag = "<?php"; static $s_progressResolution = 0.05; $prevProgressDivR = 0; $tpDpsLen = CArray::length($tpDps); for ($i0 = 0; $i0 < $tpDpsLen; $i0++) { $tpFps = CFile::reFindFilesRecursive($tpDps[$i0], "/\\.php\\d?\\z/"); $tpFpsLen = CArray::length($tpFps); for ($i1 = 0; $i1 < $tpFpsLen; $i1++) { $fileCode = CFile::read($tpFps[$i1]); if (!CString::find($fileCode, self::$ms_thirdPartyAlreadyOopWrappedMark)) { $parser = new PhpParser\Parser(new PhpParser\Lexer()); try { // Parse the code. $statements = $parser->parse($fileCode); // Wrap the code into OOP. $traverser = new PhpParser\NodeTraverser(); $mainVisitor = new CMainVisitor($wrapProtectedMethods, $wrapPrivateMethods); $traverser->addVisitor($mainVisitor); $statements = $traverser->traverse($statements); $wrappedCode = (new PhpParser\PrettyPrinter\Standard())->prettyPrint($statements); $phpTagPos = CString::indexOf($wrappedCode, $s_stdPhpTag); if ($phpTagPos == -1) { $wrappedCode = "{$s_stdPhpTag}\n\n{$wrappedCode}"; $phpTagPos = 0; } $wrappedCode = CString::insert($wrappedCode, $phpTagPos + CString::length($s_stdPhpTag), "\n\n" . self::$ms_thirdPartyAlreadyOopWrappedMark); // Save. CFile::write($tpFps[$i1], $wrappedCode); } catch (PhpParser\Error $parserError) { CShell::say("\nPhpParser: " . $tpFps[$i1] . ", at line " . $parserError->getRawLine() . ": " . $parserError->getRawMessage()); } } $progress = (double) ($i0 / $tpDpsLen + 1 / $tpDpsLen * $i1 / $tpFpsLen); $progressDivR = CMathi::floor($progress / $s_progressResolution); if ($progressDivR != $prevProgressDivR) { $perc = CMathi::round($progressDivR * $s_progressResolution * 100); CShell::speak("{$perc}%"); } $prevProgressDivR = $progressDivR; } } CShell::speak("100%"); CShell::say("Done."); $timeoutPause->end(); }
// A function used in the OOP wrapping of third-party components. function _is_non_tp_call() { static $s_thirdPartyAbsDp; if (!isset($s_thirdPartyAbsDp)) { $s_thirdPartyAbsDp = realpath($GLOBALS["PHRED_PATH_TO_THIRD_PARTY"]); } $backTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2); if (count($backTrace) < 2) { return true; } return strpos($backTrace[1]["file"], $s_thirdPartyAbsDp) !== 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // If xdebug is used, tell it that the recursion depth of 100 is not always enough. ini_set("xdebug.max_nesting_level", 4096); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Ready to initialize the framework. CSystem::initializeFramework(); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Register the aliases for the core classes. $GLOBALS["PHRED_CLASS_ALIASES"] = CConfiguration::option("classaliases"); foreach ($GLOBALS["PHRED_CLASS_ALIASES"] as $className => $alias) { class_alias($className, $alias, true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Import OOP methods for the string type. if (function_exists("register_primitive_type_handler")) { register_primitive_type_handler("string", "CUStringObject"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -