public function __construct(array $options = null) { $options = Helper::getOptions($options, ["dir" => "/tmp/query_cache", "sql" => null, "query" => null, "params" => null, "timeout" => self::DAY, "limit" => 10000, "directories" => 3, "permissions" => 0777]); $this->sql = $options["sql"]; # Store the query for other methods to use $this->query = $options["query"]; $this->params = $options["params"]; # Create the hash of the query to use as an identifier $this->hash = sha1($this->query . print_r($this->params, true)); /** * Create the path to the cache directory * Adding the number of directories specified in the options * This is because most filesystems place a limit on how many links you can have within a directory, * so this reduces that problem by spliting the cache directories into subdirectories */ $this->dir = $options["dir"] . "/"; $directories = []; for ($i = 0; $i < $options["directories"]; $i++) { if (!($dir = substr($this->hash, $i, 1))) { break; } $this->dir .= $dir . "/"; $directories[] = $dir; } $this->dir .= $this->hash; $directories[] = $this->hash; $this->timeout = $options["timeout"]; $this->rowLimit = round($options["limit"]); # Ensure a cache directory exists for this query if (!is_dir($this->dir)) { # Ensure the base directory exists if (!is_dir($options["dir"])) { mkdir($options["dir"], 0777, true); chmod($options["dir"], $options["permissions"]); } /** * We can't use the recursive feature of mkdir(), as it's permissions handling is affected by umask(). * So we create each directory individually and set the permissions using chmod(). */ $path = $options["dir"]; foreach ($directories as $dir) { $path .= "/" . $dir; if (!is_dir($path)) { mkdir($path); chmod($path, $options["permissions"]); } } } # If cache doesn't exist for this query then create it now if (!$this->isCached()) { $this->createCache(); } $data = Json::decodeFromFile($this->dir . "/.data"); $this->totalRows = $data["totalRows"]; $this->columnCount = $data["columnCount"]; $this->position = 0; $this->indexMap = false; }
/** * Get the content for parsing. * * Creates an internal dom instance. * * @param string Can either be a url with an xml/html response or string containing xml/html * * @return string The xml/html either passed in or downloaded from the url */ protected function getData($param) { if (substr($param, 0, 4) == "http") { $data = Helper::curl($param); } else { $data = $param; } $method = "load" . strtoupper($this->mode); libxml_use_internal_errors(true); $this->dom->{$method}($data); $this->errors = libxml_get_errors(); libxml_clear_errors(); return $data; }
/** * Convert the passed variable between array and the serial format (depending on the type passed). * * {@inheritDoc} */ public static function convert($data, $options = null) { $options = Helper::getOptions($options, ["cleanup" => false]); # If the data is an array the assume we are encoding it if (is_array($data)) { if ($options["cleanup"]) { $data = Helper::cleanupArray($data); } return static::encode($data); # If the data isn't an array then assume we decoding it } else { $array = static::decode($data); if ($options["cleanup"]) { $array = Helper::cleanupArray($array); } return $array; } }
/** * Get all defined environment variables. * * @return array */ public static function getVars() { if (!is_array(static::$vars)) { $path = static::path("data/env.json"); try { $vars = Json::decodeFromFile($path); } catch (\Exception $e) { $vars = []; } static::$vars = Helper::toArray($vars); } return static::$vars; }
public static function img($options) { if (!is_array($options)) { $options = array("src" => $options); } $options = Helper::getOptions($options, ["id" => "", "src" => "", "default" => "", "class" => "", "alt" => "", "title" => "", "getSize" => false]); $path = Env::getPath($options["src"]); /** * If a default image has been specifed then check if the image requested exists * If the image doesn't exist, then use the default image instead */ if ($options["default"]) { if (!file_exists($path)) { $options["src"] = $options["default"]; } } /** * If no alt text was specified then use any title text that may have been specified */ if (!$options["alt"]) { $options["alt"] = $options["title"]; } $img = "<img "; $img .= "src='" . $options["src"] . "' "; if ($options["id"]) { $img .= "id='" . $options["id"] . "' "; } if ($options["class"]) { $img .= "class='" . $options["class"] . "' "; } if ($options["alt"]) { $img .= "alt='" . Html::entities($options["alt"]) . "' "; } if ($options["title"]) { $img .= "title='" . Html::entities($options["title"]) . "' "; } if ($options["getSize"]) { list($width, $height) = getimagesize($path); if ($width > 0 && $height > 0) { $img .= "style='width:" . $width . "px;height:" . $height . "px;' "; } } $img .= ">"; return $img; }
/** * Lock some tables for exlusive write access * But allow read access to other processes */ public function lockTables($tables) { /** * Unlock any previously locked tables * This is done to provide consistency across different modes, as mysql only allows one single lock over multiple tables * Also the odbc only allows all locks to be released, not individual tables. So it makes sense to force the batching of lock/unlock operations */ $this->unlockTables(); $tables = Helper::toArray($tables); if ($this->mode == "odbc") { foreach ($tables as $table) { $table = $this->getTableName($table); $query = "LOCK TABLE " . $table . " IN EXCLUSIVE MODE ALLOW READ"; $this->query($query); } # If none of the locks failed then report success return true; } foreach ($tables as &$table) { $table = $this->getTableName($table); } unset($table); if ($this->mode == "mysql") { $query = "LOCK TABLES " . implode(",", $tables) . " WRITE"; return $this->query($query); } if (in_array($this->mode, ["postgres", "redshift"], true)) { $query = "LOCK TABLE " . implode(",", $tables) . " IN EXCLUSIVE MODE"; return $this->query($query); } throw new \Exception("lockTables() not supported in this mode (" . $this->mode . ")"); }