/** * @param string $adapter * @param bool $new * @return MySQL\Abstracts\MySQLi|MySQL\Abstracts\None */ public static function getInstance($adapter = self::INST_DEFAULT, $new = false) { if ($adapter == self::INST_AUTO) { static $auto = null; if (!is_null($auto)) { return self::getInstance($auto, $new); } if (MySQLi::isAvailable()) { Debugger::addLine("MySQL module: MySQLi"); return self::getInstance($auto = self::INST_MYSQLI, $new); } else { Debugger::addLine("No suitable MySQL module detected"); return self::getInstance($auto = self::INST_NONE, $new); } } if (!$new and isset(self::$adapters[$adapter])) { return self::$adapters[$adapter]; } switch ($adapter) { case self::INST_MYSQLI: $obj = new MySQLi(); break; default: $obj = new None(); } if (!$new) { self::$adapters[$adapter] = $obj; } return $obj; }
/** * Find controller and action for current URI * @throws Exception */ public static function find() { if (self::loadCache()) { Debugger::addLine('Cached controller ' . self::$controllerClass . ' from ' . self::$controllerFile); return; } $uri = trim(Envi::getUri(), '/'); $parts = $uri ? explode('/', $uri) : []; self::getResource($parts); $controllerUriParts = $parts; if (!(self::$controllerFile = self::findController($parts))) { self::saveCache('404'); throw new HttpError(404); } self::$controllerUri = '/' . implode('/', sizeof($parts) ? array_slice($controllerUriParts, 0, -sizeof($parts)) : $controllerUriParts); /** @noinspection PhpIncludeInspection */ include_once self::$controllerFile; if (!class_exists(self::$controllerClass)) { throw new Exception('Error! Controller class ' . self::$controllerClass . ' not found'); } self::findAction($parts); self::$parameters = $parts; self::saveCache('action'); Debugger::addLine('Selected controller ' . self::$controllerClass . ' from ' . self::$controllerFile); }
public function dispatch() { if (!\Difra\Debugger::isEnabled()) { throw new \Difra\View\HttpError(404); } \Difra\View::$instance = 'adm'; }
/** * Convert LESS to CSS * @param string $string * @return string */ public static function compile($string) { self::init(); $parser = new \Less_Parser(); $parser->SetOptions(['compress' => !Debugger::isEnabled()]); $parser->parse($string); return $parser->getCss(); }
/** * Choose most suitable file * @param $file * @return mixed|string */ private function getFile($file) { $debuggerEnabled = Debugger::isEnabled(); if (!$debuggerEnabled and !empty($file['min'])) { return file_get_contents($file['min']); } elseif (!$debuggerEnabled and !empty($file['raw'])) { return Minify::getInstance($this->type)->minify(file_get_contents($file['raw'])); } elseif ($debuggerEnabled and !empty($file['raw'])) { return file_get_contents($file['raw']); } elseif ($debuggerEnabled and !empty($file['min'])) { return file_get_contents($file['min']); } return ''; }
/** * @param \DOMDocument $xml * @param bool|string $specificInstance * @param bool $dontEcho * @param bool $dontFillXML * @param bool $normalize * @return bool|string * @throws Exception */ public static function render(&$xml, $specificInstance = false, $dontEcho = false, $dontFillXML = false, $normalize = true) { if ($specificInstance) { $instance = $specificInstance; } elseif (self::$instance) { $instance = self::$instance; } else { $instance = 'main'; } Debugger::addLine("Render start (instance '{$instance}')"); if (!($resource = Resourcer::getInstance('xslt')->compile($instance))) { throw new Exception("XSLT resource not found"); } $xslDom = new \DomDocument(); $xslDom->resolveExternals = true; $xslDom->substituteEntities = true; if (!$xslDom->loadXML($resource)) { throw new Exception("XSLT load problem for instance '{$instance}'"); } $xslProcessor = new \XSLTProcessor(); $xslProcessor->importStylesheet($xslDom); if (!$dontFillXML and !HttpError::$error and !Debugger::$shutdown) { View\XML::fillXML($xml, $instance); } // transform template if ($html = $xslProcessor->transformToDoc($xml)) { if ($normalize) { $html = self::normalize($html); } else { $html->formatOutput = true; $html = $html->saveXML(); } if ($dontEcho) { return $html; } echo $html; self::$rendered = true; if (Debugger::isEnabled()) { echo '<!-- Page rendered in ' . Debugger::getTimer() . ' seconds -->'; } if (function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } } else { $errormsg = libxml_get_errors(); //error_get_last(); throw new Exception($errormsg ? $errormsg['message'] : "Can't render templates"); } return true; }
/** * @backupGlobals enabled */ public function test_actions() { \Difra\Debugger::disable(); \Difra\Ajaxer::clean(); $actions = []; \Difra\Ajaxer::notify('notification message'); $actions[] = ['action' => 'notify', 'message' => 'notification message', 'lang' => ['close' => \Difra\Locales::get('notifications/close')]]; \Difra\Ajaxer::display('<span>test</span>'); $actions[] = ['action' => 'display', 'html' => '<span>test</span>']; \Difra\Ajaxer::error('error message <span>test</span>'); $actions[] = ['action' => 'error', 'message' => 'error message <span>test</span>', 'lang' => ['close' => \Difra\Locales::get('notifications/close')]]; \Difra\Ajaxer::required('element'); $actions[] = ['action' => 'require', 'name' => 'element']; \Difra\Ajaxer::invalid('inv1'); $actions[] = ['action' => 'invalid', 'name' => 'inv1']; \Difra\Ajaxer::invalid('inv2'); $actions[] = ['action' => 'invalid', 'name' => 'inv2']; \Difra\Ajaxer::status('field1', 'bad value', 'problem'); $actions[] = ['action' => 'status', 'name' => 'field1', 'message' => 'bad value', 'classname' => 'problem']; \Difra\Ajaxer::redirect('/some/page'); $actions[] = ['action' => 'redirect', 'url' => '/some/page']; $_SERVER['HTTP_REFERER'] = '/current/page'; \Difra\Ajaxer::refresh(); $actions[] = ['action' => 'redirect', 'url' => '/current/page']; \Difra\Ajaxer::reload(); $actions[] = ['action' => 'reload']; \Difra\Ajaxer::load('someid', 'some <b>content</b>'); $actions[] = ['action' => 'load', 'target' => 'someid', 'html' => 'some <b>content</b>']; \Difra\Ajaxer::close(); $actions[] = ['action' => 'close']; \Difra\Ajaxer::reset(); $actions[] = ['action' => 'reset']; \Difra\Envi::setUri('/current/page'); \Difra\Ajaxer::confirm('Are you sure?'); $actions[] = ['action' => 'display', 'html' => '<form action="/current/page" class="ajaxer"><input type="hidden" name="confirm" value="1"/>' . '<div>Are you sure?</div>' . '<input type="submit" value="' . \Difra\Locales::get('ajaxer/confirm-yes') . '"/>' . '<input type="button" value="' . \Difra\Locales::get('ajaxer/confirm-no') . '" onclick="ajaxer.close(this)"/>' . '</form>']; $this->assertEquals(\Difra\Ajaxer::getResponse(), json_encode(['actions' => $actions], \Difra\Ajaxer::getJsonFlags())); \Difra\Ajaxer::clean(); $this->assertEquals(\Difra\Ajaxer::getResponse(), '[]'); $this->assertFalse(\Difra\Ajaxer::hasProblem()); \Difra\Ajaxer::reload(); \Difra\Ajaxer::clean(true); $this->assertEquals(\Difra\Ajaxer::getResponse(), '[]'); $this->assertTrue(\Difra\Ajaxer::hasProblem()); }
/** * Choose view depending on request type */ public static final function start() { $controller = Controller::getInstance(); if (Controller::hasUnusedParameters()) { $controller->putExpires(true); throw new HttpError(404); } elseif (!is_null(self::$output)) { $controller->putExpires(); header('Content-Type: ' . self::$outputType . '; charset="utf-8"'); echo self::$output; View::$rendered = true; } elseif (Debugger::isEnabled() and isset($_GET['xml']) and $_GET['xml']) { if ($_GET['xml'] == '2') { View\XML::fillXML(); } header('Content-Type: text/xml; charset="utf-8"'); $controller->xml->formatOutput = true; $controller->xml->encoding = 'utf-8'; echo rawurldecode($controller->xml->saveXML()); View::$rendered = true; } elseif (!View::$rendered and Request::isAjax()) { $controller->putExpires(); // should be application/json, but opera doesn't understand it and offers to save file to disk header('Content-type: text/plain'); echo Ajaxer::getResponse(); View::$rendered = true; } elseif (!View::$rendered) { $controller->putExpires(); try { View::render($controller->xml); } catch (HttpError $ex) { if (!Debugger::isConsoleEnabled()) { throw new HttpError(500); } else { echo Debugger::debugHTML(true); die; } } } }
/** * @param \SimpleXMLElement $node * @param string $href * @param string $prefix * @param string $instance * @internal param string $url */ private function recursiveProcessor($node, $href, $prefix, $instance) { /** @var \SimpleXMLElement $subNode */ foreach ($node as $subname => $subNode) { /** @noinspection PhpUndefinedFieldInspection */ if ($subNode->attributes()->sup and $subNode->attributes()->sup == '1') { if (!Debugger::isEnabled()) { $subNode->addAttribute('hidden', 1); } } $newHref = "{$href}/{$subname}"; $newPrefix = "{$prefix}_{$subname}"; $subNode->addAttribute('id', $newPrefix); /** @noinspection PhpUndefinedFieldInspection */ if (!isset($subNode->attributes()->href)) { $subNode->addAttribute('href', $newHref); } $subNode->addAttribute('pseudoHref', $newHref); $subNode->addAttribute('xpath', 'locale/menu/' . $instance . '/' . $newPrefix); $this->recursiveProcessor($subNode, $newHref, $newPrefix, $instance); } }
/** * Set X-Accel-Expires header for web server-side caching * @param bool|int $ttl */ public function putExpires($ttl = null) { if (Debugger::isEnabled()) { return; } if (is_null($ttl)) { $ttl = $this->cache; } if ($ttl === true) { $ttl = self::DEFAULT_CACHE; } if (!$ttl or !is_numeric($ttl) or $ttl < 0) { return; } View::addExpires($ttl); }
/** * Fill output XML with some common data * @param \DOMDocument|null $xml * @param null $instance */ public static function fillXML(&$xml = null, $instance = null) { $controller = Controller::getInstance(); if (is_null($xml)) { $xml = $controller->xml; $node = $controller->realRoot; } else { $node = $xml->documentElement; } Debugger::addLine('Filling XML data for render: Started'); // TODO: sync this with Envi::getState() $node->setAttribute('lang', Envi\Setup::getLocale()); $node->setAttribute('site', Envi::getSubsite()); $node->setAttribute('host', $host = Envi::getHost()); $node->setAttribute('mainhost', $mainhost = Envi::getHost(true)); $node->setAttribute('protocol', Envi::getProtocol()); $node->setAttribute('fullhost', Envi::getURLPrefix()); $node->setAttribute('instance', $instance ? $instance : View::$instance); $node->setAttribute('uri', Envi::getUri()); $node->setAttribute('controllerUri', Action::getControllerUri()); if ($host != $mainhost) { $node->setAttribute('urlprefix', Envi::getURLPrefix(true)); } // get user agent Envi\UserAgent::getUserAgentXML($node); // ajax flag $node->setAttribute('ajax', (Request::isAjax() or isset($_SERVER['HTTP_X_REQUESTED_WITH']) and $_SERVER['HTTP_X_REQUESTED_WITH'] == 'SwitchPage') ? '1' : '0'); $node->setAttribute('switcher', (!$controller->cache and isset($_SERVER['HTTP_X_REQUESTED_WITH']) and $_SERVER['HTTP_X_REQUESTED_WITH'] == 'SwitchPage') ? '1' : '0'); // build and version number $node->setAttribute('build', Version::getBuild()); $node->setAttribute('framework', Version::getFrameworkVersion(false)); $node->setAttribute('frameworkLong', Version::getFrameworkVersion(true)); // date /** @var $dateNode \DOMElement */ $dateNode = $node->appendChild($xml->createElement('date')); $dateKeys = ['d', 'e', 'A', 'a', 'm', 'B', 'b', 'Y', 'y', 'c', 'x', 'H', 'M', 'S']; $dateValues = explode('|', strftime('%' . implode('|%', $dateKeys))); $dateCombined = array_combine($dateKeys, $dateValues); $dateNode->setAttribute('ts', time()); foreach ($dateCombined as $k => $v) { $dateNode->setAttribute($k, $v); } // debug flag $node->setAttribute('debug', Debugger::isEnabled() ? '1' : '0'); // config values (for js variable) $configNode = $node->appendChild($xml->createElement('config')); Envi::getStateXML($configNode); // menu if ($menuResource = Resourcer::getInstance('menu')->compile(View::$instance)) { $menuXML = new \DOMDocument(); $menuXML->loadXML($menuResource); $node->appendChild($xml->importNode($menuXML->documentElement, true)); } // auth Auth::getInstance()->getAuthXML($node); // locale Locales::getInstance()->getLocaleXML($node); // Add config js object $config = Envi::getState(); $confJS = ''; foreach ($config as $k => $v) { $confJS .= "config.{$k}='" . addslashes($v) . "';"; } $node->setAttribute('jsConfig', $confJS); Debugger::addLine('Filling XML data for render: Done'); Debugger::debugXML($node); }
/** * Выбирает рабочий cdn хост */ public function selectHost() { $this->_getSettings(); $db = \Difra\MySQL::getInstance(); $res = null; $stage = null; // stage 1 — select from 'ok' hosts with softer load of new cdn hosts try { $queryWrk = "SELECT `id`, `host`, `port` FROM `cdn_hosts_work`\n\t\t\t\tWHERE (`status`='ok'\n\t\t\t\tOR `failed`<DATE_SUB(NOW(),INTERVAL " . intval($this->settings['failtime']) . " MINUTE))\n\t\t\t\tAND `created`<DATE_SUB(NOW(),INTERVAL " . intval(rand(0, 24)) . " HOUR)\n\t\t\t\tORDER BY `selected`\n\t\t\t\tLIMIT 1"; $res = $db->fetchRow($queryWrk); if (!$res) { $db->query('REPLACE INTO `cdn_hosts_work` SELECT * FROM `cdn_hosts`'); $res = $db->fetchRow($queryWrk); } $stage = 1; } catch (\Difra\Exception $ex) { } // stage 2 — select from 'ok' hosts without softer load of new cdn hosts if (!$res) { try { $query = "SELECT `id`, `host`, `port` FROM `cdn_hosts_work`\n\t\t\t\tWHERE `status`='ok'\n\t\t\t\tAND `failed`<DATE_SUB(NOW(),INTERVAL " . intval($this->settings['failtime']) . " MINUTE)\n\t\t\t\tORDER BY `selected`\n\t\t\t\tLIMIT 1"; $res = $db->fetchRow($query); $stage = 2; } catch (\Difra\Exception $ex) { } } // stage 3 — select from busy hosts if (!$res) { try { $query = "SELECT `id`, `host`, `port` FROM `cdn_hosts_work`\n\t\t\t\tWHERE `status`='busy'\n\t\t\t\tORDER BY `selected` DESC\n\t\t\t\tLIMIT 1"; $res = $db->fetchRow($query); $stage = 3; } catch (\Difra\Exception $ex) { } } // stage 4 - select from hosts that haven't been checked for a long time if (!$res) { try { $query = "SELECT `id`, `host`, `port` FROM `cdn_hosts`\n\t\t\t\tWHERE `failed`<DATE_SUB(NOW(),INTERVAL " . intval($this->settings['failtime']) . " MINUTE)\n\t\t\t\tORDER BY `selected`\n\t\t\t\tLIMIT 1"; $res = $db->fetchRow($query); $stage = 4; } catch (\Difra\Exception $ex) { } } if (!empty($res)) { $rootNode = \Difra\Action::getInstance()->controller->root; $rootNode->setAttribute('cdn_host', $res['host'] . ':' . $res['port']); $rootNode->setAttribute('cdn_host_id', $res['id']); $this->_updateSelected($res['id'], $res['host'] . ':' . $res['port']); if (\Difra\Debugger::getInstance()->isEnabled()) { $rootNode->setAttribute('cdn_stage', $stage); } return; } }
/** * Fetch data from database * @param string $query * @param bool $replica Allow reading data from db replica * @return array */ public function fetch($query, $replica = false) { $this->connect(); Debugger::prepareDBLine(); $result = $this->realFetch($query, $replica); Debugger::addDBLine('MySQL', $query); $this->queries++; return $result; }
/** * Compile resource * @param string $instance * @param bool $withSources * @throws Exception * @return string */ private function realCompile($instance, $withSources = false) { Debugger::addLine("Resource {$this->type}/{$instance} compile started"); $res = false; if ($this->find($instance)) { $this->processDirs($instance); $res = $this->processData($instance, $withSources); } $res = $this->processText($res); Debugger::addLine("Resource {$this->type}/{$instance} compile finished"); return $res; }
/** * Commit transaction * @return bool */ public function commit() { $this->transaction = false; $result = $this->pdo->commit(); if (Debugger::isEnabled()) { Debugger::addDBLine('DB', 'Transaction commited in ' . number_format((microtime(true) - $this->transaction) * 1000, 1) . ' ms'); } return $result; }
/** * Is debugging enabled? * @return bool */ protected static function isDebug() { return \Difra\Debugger::isEnabled(); }