%PDF- %PDF-
Direktori : /home/vacivi36/ava/admin/tool/customlang/classes/local/mlang/ |
Current File : /home/vacivi36/ava/admin/tool/customlang/classes/local/mlang/phpparser.php |
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Mlang PHP based on David Mudrak phpparser for local_amos. * * @package tool_customlang * @copyright 2020 Ferran Recio <ferran@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace tool_customlang\local\mlang; use coding_exception; use moodle_exception; /** * Parser of Moodle strings defined as associative array. * * Moodle core just includes this file format directly as normal PHP code. However * for security reasons, we must not do this for files uploaded by anonymous users. * This parser reconstructs the associative $string array without actually including * the file. */ class phpparser { /** @var holds the singleton instance of self */ private static $instance = null; /** * Prevents direct creation of object */ private function __construct() { } /** * Prevent from cloning the instance */ public function __clone() { throw new coding_exception('Cloning os singleton is not allowed'); } /** * Get the singleton instance fo this class * * @return phpparser singleton instance of phpparser */ public static function get_instance(): phpparser { if (is_null(self::$instance)) { self::$instance = new phpparser(); } return self::$instance; } /** * Parses the given data in Moodle PHP string format * * Note: This method is adapted from local_amos as it is highly tested and robust. * The priority is keeping it similar to the original one to make it easier to mantain. * * @param string $data definition of the associative array * @param int $format the data format on the input, defaults to the one used since 2.0 * @return langstring[] array of langstrings of this file */ public function parse(string $data, int $format = 2): array { $result = []; $strings = $this->extract_strings($data); foreach ($strings as $id => $text) { $cleaned = clean_param($id, PARAM_STRINGID); if ($cleaned !== $id) { continue; } $text = langstring::fix_syntax($text, 2, $format); $result[] = new langstring($id, $text); } return $result; } /** * Low level parsing method * * Note: This method is adapted from local_amos as it is highly tested and robust. * The priority is keeping it similar to the original one to make it easier to mantain. * * @param string $data * @return string[] the data strings */ protected function extract_strings(string $data): array { $strings = []; // To be returned. if (empty($data)) { return $strings; } // Tokenize data - we expect valid PHP code. $tokens = token_get_all($data); // Get rid of all non-relevant tokens. $rubbish = [T_WHITESPACE, T_INLINE_HTML, T_COMMENT, T_DOC_COMMENT, T_OPEN_TAG, T_CLOSE_TAG]; foreach ($tokens as $i => $token) { if (is_array($token)) { if (in_array($token[0], $rubbish)) { unset($tokens[$i]); } } } $id = null; $text = null; $line = 0; $expect = 'STRING_VAR'; // The first expected token is '$string'. // Iterate over tokens and look for valid $string array assignment patterns. foreach ($tokens as $token) { $foundtype = null; $founddata = null; if (is_array($token)) { $foundtype = $token[0]; $founddata = $token[1]; if (!empty($token[2])) { $line = $token[2]; } } else { $foundtype = 'char'; $founddata = $token; } if ($expect == 'STRING_VAR') { if ($foundtype === T_VARIABLE and $founddata === '$string') { $expect = 'LEFT_BRACKET'; continue; } else { // Allow other code at the global level. continue; } } if ($expect == 'LEFT_BRACKET') { if ($foundtype === 'char' and $founddata === '[') { $expect = 'STRING_ID'; continue; } else { throw new moodle_exception('Parsing error. Expected character [ at line '.$line); } } if ($expect == 'STRING_ID') { if ($foundtype === T_CONSTANT_ENCAPSED_STRING) { $id = $this->decapsulate($founddata); $expect = 'RIGHT_BRACKET'; continue; } else { throw new moodle_exception('Parsing error. Expected T_CONSTANT_ENCAPSED_STRING array key at line '.$line); } } if ($expect == 'RIGHT_BRACKET') { if ($foundtype === 'char' and $founddata === ']') { $expect = 'ASSIGNMENT'; continue; } else { throw new moodle_exception('Parsing error. Expected character ] at line '.$line); } } if ($expect == 'ASSIGNMENT') { if ($foundtype === 'char' and $founddata === '=') { $expect = 'STRING_TEXT'; continue; } else { throw new moodle_exception('Parsing error. Expected character = at line '.$line); } } if ($expect == 'STRING_TEXT') { if ($foundtype === T_CONSTANT_ENCAPSED_STRING) { $text = $this->decapsulate($founddata); $expect = 'SEMICOLON'; continue; } else { throw new moodle_exception( 'Parsing error. Expected T_CONSTANT_ENCAPSED_STRING array item value at line '.$line ); } } if ($expect == 'SEMICOLON') { if (is_null($id) or is_null($text)) { throw new moodle_exception('Parsing error. NULL string id or value at line '.$line); } if ($foundtype === 'char' and $founddata === ';') { if (!empty($id)) { $strings[$id] = $text; } $id = null; $text = null; $expect = 'STRING_VAR'; continue; } else { throw new moodle_exception('Parsing error. Expected character ; at line '.$line); } } } return $strings; } /** * Given one T_CONSTANT_ENCAPSED_STRING, return its value without quotes * * Also processes escaped quotes inside the text. * * Note: This method is taken directly from local_amos as it is highly tested and robust. * * @param string $text value obtained by token_get_all() * @return string value without quotes */ protected function decapsulate(string $text): string { if (strlen($text) < 2) { throw new moodle_exception('Parsing error. Expected T_CONSTANT_ENCAPSED_STRING in decapsulate()'); } if (substr($text, 0, 1) == "'" and substr($text, -1) == "'") { // Single quoted string. $text = trim($text, "'"); $text = str_replace("\'", "'", $text); $text = str_replace('\\\\', '\\', $text); return $text; } else if (substr($text, 0, 1) == '"' and substr($text, -1) == '"') { // Double quoted string. $text = trim($text, '"'); $text = str_replace('\"', '"', $text); $text = str_replace('\\\\', '\\', $text); return $text; } else { throw new moodle_exception( 'Parsing error. Unexpected quotation in T_CONSTANT_ENCAPSED_STRING in decapsulate(): '.$text ); } } }