Edit file File name : StateChecker.php Content :<?php /** * * SugarCRM Community Edition is a customer relationship management program developed by * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. * * SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd. * Copyright (C) 2011 - 2018 SalesAgility Ltd. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by the * Free Software Foundation with the addition of the following permission added * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. * * This program 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 Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License along with * this program; if not, see http://www.gnu.org/licenses or write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. * * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License version 3. * * In accordance with Section 7(b) of the GNU Affero General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not * reasonably feasible for technical reasons, the Appropriate Legal Notices must * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". */ namespace SuiteCRM; use DBManager; use DBManagerFactory; use mysqli_result; use MysqliManager; use RecursiveIteratorIterator; if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } include_once __DIR__ . '/StateCheckerDirectoryIterator.php'; /** * StateChecker * * Save and check the system state and reports you about any state change in the following: * * - Database * - File system * - Super globals * - PHP error reporting level * - PHP configuration options * * See more about the StateChecker configuration at the StateCheckerConfig class. * * @author SalesAgility */ class StateChecker { /** * * @var DBManager */ protected $db; /** * * @var array */ protected $hashes; /** * * @var string */ protected $lastHash; /** * * @var array */ protected $traces; /** * * @var integer */ protected $memoryLimit; /** * * @var array */ protected $excludedTables = ['job_queue', 'schedulers']; /** * * @throws StateCheckerException */ public function __construct() { if (!$this->db = DBManagerFactory::getInstance()) { throw new StateCheckerException('DBManagerFactory get instace failure'); } if (!($this->db instanceof MysqliManager)) { throw new StateCheckerException('Incompatible DB type, only supported: mysqli'); } $this->resetHashes(); $this->resetTraces(); if (StateCheckerConfig::get('redefineMemoryLimit')) { $this->memoryLimit = ini_get('memory_limit'); ini_set('memory_limit', -1); } if (StateCheckerConfig::get('autoRun')) { $this->getStateHash(); } } /** * * @return array traces * @throws StateCheckerException */ public function getTraces() { if (StateCheckerConfig::get('saveTraces')) { throw new StateCheckerException('Trace information is not saved, use StateCheckerConfig::get(\'saveTraces\') as true'); } return $this->traces; } /** * */ public function __destruct() { if (StateCheckerConfig::get('redefineMemoryLimit')) { ini_set('memory_limit', $this->memoryLimit); } } /** * resetTraces */ protected function resetTraces() { $this->traces = []; } /** * resetHashes */ protected function resetHashes() { $this->hashes = []; } /** * * @param string $key * @return boolean */ protected function isDetailedKey($key) { $detailedKey = preg_match('/\w+\:\:/', $key); return $detailedKey; } /** * * @param string $hash * @param string $key * @return boolean */ protected function checkHash($hash, $key) { $detailedKey = $this->isDetailedKey($key); $needToStore = !$detailedKey || ($detailedKey && StateCheckerConfig::get('storeDetails')); if (!isset($this->hashes[$key])) { if ($needToStore) { $this->hashes[$key] = $hash; } } if ($needToStore) { $match = $this->hashes[$key] == $hash; } else { $match = true; } return $match; } /** * * @param mixed $data should be serializable * @param string $key * @return string * @throws StateCheckerException */ protected function getHash($data, $key) { $serialized = serialize($data); if (!$serialized) { throw new StateCheckerException('Serialize object failure'); } $hash = null; if (!in_array($key, StateCheckerConfig::get('testsFailureExcludeKeys'))) { $hash = md5($serialized); } $this->lastHash = $hash; if (!$this->checkHash($hash, $key)) { throw new StateCheckerException('Hash doesn\'t match at key "' . $key . '".'); } if (StateCheckerConfig::get('saveTraces')) { $this->traces[$key][] = debug_backtrace(); } return $hash; } /** * * @return string */ public function getLastHash() { return $this->lastHash; } // ------------ DATABASE ---------------- /** * * @param mysqli_result $resource * @return array */ protected function getMysqliResults(mysqli_result $resource) { $rows = []; while ($row = $resource->fetch_assoc()) { $rows[] = $row; } return $rows; } /** * * @return array * @throws StateCheckerException */ protected function getDatabaseTables() { $tables = $this->db->tablesLike(''); if (!$tables) { throw new StateCheckerException('get tables failure'); } return $tables; } /** * * @return string */ protected function getDatabaseHash() { $tables = $this->getDatabaseTables(); $hashes = []; foreach ($tables as $table) { if (!in_array($table, $this->excludedTables)) { $rows = $this->getMysqliResults($this->db->query('SELECT * FROM ' . $table)); $hashes[] = $this->getHash($rows, 'database::' . $table); } } $hash = $this->getHash($hashes, 'database'); return $hash; } // ------------- FILE SYSTEM --------------- /** * * @param string $name filename * @return boolean */ protected function isExcludedFile($name) { foreach (StateCheckerConfig::get('fileExludeRegexes') as $regex) { if (preg_match($regex, $name)) { return true; } } return false; } /** * * @param string $path * @return array * @throws StateCheckerException */ protected function getFiles($path = '.') { clearstatcache(true); $realpath = realpath($path); if (!$realpath) { throw new StateCheckerException('Real path can not resolved for: ' . $path); } $objects = new RecursiveIteratorIterator(new StateCheckerDirectoryIterator($realpath), RecursiveIteratorIterator::SELF_FIRST); $files = []; foreach ($objects as $name => $object) { if (!$object->isDir() && !$this->isExcludedFile($name)) { $fileObject = $object; // $fileObject->modifyTime = filemtime($name); $fileObject->fileSize = filesize($name); $fileObject->hash = $this->getHash((array)$fileObject, 'filesys::' . $fileObject); $files[] = $name; } } return $files; } /** * * @return string */ protected function getFilesystemHash() { $files = $this->getFiles(__DIR__ . '/../'); $hash = $this->getHash($files, 'filesys'); return $hash; } // -------------- SUPERGLOBALS ----------------- /** * * @return string */ protected function getSuperGlobalsHash() { $globals = []; foreach (StateCheckerConfig::get('globalKeys') as $globalKey) { $globals[$globalKey] = $this->getHash(isset($GLOBALS[$globalKey]) ? $GLOBALS[$globalKey] : null, 'globals::' . $globalKey); } $hash = $this->getHash($globals, 'globals'); return $hash; } // -------------- ERROR LEVEL ------------- /** * * @return string hash */ protected function getErrorLevelHash() { $level = error_reporting(); $hash = $this->getHash($level, 'errlevel'); return $hash; } // ------------- PHP CONFIGURATION OPTIONS --------------- protected function getPHPConfigOptionsHash() { $configOptions = StateSaver::getPHPConfigOptions(); $hash = $this->getHash($configOptions, 'phpconfopt'); return $hash; } // -------------- ALL ---------------------- protected $lashHashAll = null; public function getLastHashAll() { return $this->lashHashAll; } /** * Retrieve a hash of all * * @return string hash */ public function getStateHash() { $hashes['database'] = $this->getDatabaseHash(); $hashes['filesys'] = $this->getFilesystemHash(); $hashes['globals'] = $this->getSuperGlobalsHash(); $hashes['errlevel'] = $this->getErrorLevelHash(); $hashes['phpconf'] = $this->getPHPConfigOptionsHash(); $this->lashHashAll = $this->getHash($hashes, 'state'); return $this->lashHashAll; } } Save