/** * Instantiates a new hasher object and set the salt to the supplied one. * The constructor will throw an exception if SIP 3rd party module isn't * installed in PHP, or if the hash is not a string or if its length is not * 16 exactly -- a requirement of this hashing algorithm. * * @link https://github.com/jedisct1/siphash-php SIP 3rd party module * @param string $salt must be a 16-byte string */ public function __construct($salt) { // Check for SIP module. Assert::that(['condition' => function_exists('sip_hash'), 'message' => 'The SIP 3rd party module is not installed', 'type' => Error::TYPE_RUNTIME]); // The salt must be exactly 16-bytes long. Assert::that(['condition' => is_string($salt) && 16 === strlen($salt), 'message' => 'The SIP hash value must be a 16-byte string', 'type' => Error::TYPE_ARGUMENT]); // All good, continue execution. parent::__construct($salt); }
/** * Instantiates this class with the specified service name and log file path. * If the file doesn't exist, and $autoCreate is TRUE, then the file will be * created. Note that the target directory *must* exist before the file will * be created, or else an exception will be thrown. * * @param string $serviceName of this log file * @param string $filePath to log file * @param boolean $autoCreate TRUE to create the file if missing */ public function __construct($serviceName, $filePath, $autoCreate = true) { // Always call parent constructor. parent::__construct($serviceName); Assert::that(['condition' => !System::isDir($filePath), 'message' => 'The error log file path [%s] cannot be a directory', 'args' => [$filePath], 'type' => Error::TYPE_ARGUMENT]); if (!System::isFile($filePath)) { Assert::that(['condition' => $autoCreate, 'message' => 'The error log file [%s] is not present', 'args' => [$filePath], 'type' => Error::TYPE_ARGUMENT]); Assert::that(['condition' => System::touch($filePath), 'message' => 'The error log file [%s] cannot be created', 'args' => [$filePath], 'type' => Error::TYPE_RUNTIME]); } // At this point, a production environment should be already set up to // include this file or create it when necessary. $this->fileHandle = System::openFile($filePath, 'a'); Assert::that(['condition' => $this->fileHandle, 'message' => 'Unable to open error log file [%s] for writing', 'args' => [$filePath], 'type' => Error::TYPE_RUNTIME]); }
/** * Loads the associated PHP class script for the specified driver. * * @param string $driver to load * @return \Fine47\DbOne\Prototype instance of a specified driver * @throws \Fine47\DbOne\Error */ public static function getDriver($driver) { // Normalize driver name. $driver = @strtolower(trim($driver)); // The 'prototype' driver is built-in. Assert::that(['condition' => self::PROTOTYPE !== $driver, 'message' => 'Driver [%s] is built-in and cannot be used.', 'args' => [$driver], 'type' => Error::TYPE_DATABASE]); // Load the driver script once. if (!isset(self::$instances[$driver])) { // Class name has a first uppercase letter. $className = '\\Fine47\\DbOne\\Drivers\\' . ucfirst($driver); // Create a new instance of the driver. self::$instances[$driver] = new $className(); } return self::$instances[$driver]; }
/** * @see \Fine47\MicroRouter\Responses\Http::serveImpl() */ protected function serveImpl() { // Create a temporary file to hold the output buffer. $tempPath = System::tempFile(); try { // Save output buffer as JSON. Assert::that(['condition' => false !== file_put_contents($tempPath, Json::encode($this->getBody())), 'message' => 'Unable to serve the response body', 'type' => Error::TYPE_RUNTIME, 'magic' => 0xeb73]); // Close the file handle and outputs its contents. Assert::that(['condition' => false !== readfile($tempPath, false), 'message' => 'Unable to serve the response body', 'type' => Error::TYPE_RUNTIME, 'magic' => 0xeb74]); } finally { // Deletes temporary file. @unlink($tempPath); } // Once the body is served, it cannot be re-served again. $this->shutdown(); }
/** * Guarantees that this image instance hasn't been destroyed yet. * * @throws \Fine47\Exceptions\ImageError */ protected function assertActive() { Assert::that(['condition' => $this->resource && is_resource($this->resource), 'message' => 'This image has already been destroyed', 'type' => Error::TYPE_IMAGE, 'magic' => 0x777e]); }
/** * Auxiliary method to ensure that the output body hasn't been served yet. If * it has, the method will throw an exception. */ protected function ensureNotServed() { Assert::that(['condition' => !$this->served, 'message' => 'Response body already served', 'type' => Error::TYPE_RUNTIME]); }
/** * Instantiates a new action corresponding to the supplied handler script. * * @param string $routePath digging starts from this top-level directory * @param string $matchUri farthest path to traverse * @param string $scriptPath where handler resides * @param array $params for the action * @param \Fine47\MicroRouter\Interfaces\Query $query for the action * @return \Fine47\MicroRouter\Interfaces\Action */ protected function getHandlerAction($routePath, $matchUri, $scriptPath, array $params, Interfaces\Query $query) { // Load this action's class. The returned value is the class's name. $actionClass = (require_once $scriptPath); // Trim any spaces. $actionClass = @trim($actionClass); // Because a back-slash is used to escape characters, we also accept forward // slashes to set the namespace. $actionClass = @str_replace('/', '\\', $actionClass); // Make the namespace absolute by adding a starting back slash. if ('' !== $actionClass && '\\' !== $actionClass[0]) { $actionClass = '\\' . $actionClass; } // Test if the action class is valid. Assert::that(['condition' => $actionClass && class_exists($actionClass), 'message' => 'The handler class [%s] cannot be found' . ' (did you include a namespace?)', 'args' => [$actionClass], 'type' => Error::TYPE_PARSE, 'magic' => 0xf776]); // TODO: Find the filters for this action. $filters = $this->getActionFilters($routePath, $matchUri, $query); // Instantiate this class. $action = new $actionClass($query, $params, $filters); // Test if the action class is valid. Assert::that(['condition' => $action instanceof Actions\Files, 'message' => 'The handler script [%s] must inherit from ' . 'Actions\\Files class', 'args' => [$scriptPath], 'type' => Error::TYPE_PARSE, 'magic' => 0x3ba7]); return $action; }
/** * Instantiates a new request identified by the specified URI. A base URI must * be provided also to govern the base URI to anchor to (ex.: '/', '/api'). * * Note that getUri() will return the evaluated request URI after cropping the * leading base URI. * * @param string $baseUri for this request * @param string $uri of this request (including leading base URI) * @see \Fine47\MicroRouter\Interfaces\Request::getUri() */ public function __construct($baseUri, $uri = null) { // Normalize the base URI to be a string. $baseUri = @trim($baseUri); // A base URI must start with a '/' Assert::that(['condition' => $baseUri && '/' === $baseUri[0], 'message' => 'Base URI path must start with a / character', 'type' => Error::TYPE_ARGUMENT]); // Normalize it by adding a trailing slash character. $baseUri = @rtrim($baseUri, '/') . '/'; // Use default request URI if it's not provided. if (null === $uri) { $uri = @trim($_SERVER['REQUEST_URI']); } // A request URI must start with a '/' Assert::that(['condition' => $uri && '/' === $uri[0], 'message' => 'Request URI must start with a / character', 'type' => Error::TYPE_ARGUMENT]); // Get base URI's length. $baseUriLen = strlen($baseUri); // Strip base URI from request URI. if (!strcmp(substr($uri, 0, $baseUriLen), $baseUri)) { $uri = substr($uri, $baseUriLen); } // Ensure that the resulting request URI (without base URI) is valid. Assert::that(['condition' => $this->isValidUri($uri), 'message' => 'Request URI is invalid', 'type' => Error::TYPE_ARGUMENT, 'magic' => 0x8245]); // Normalize request URI by removing leading and trailing slash characters. $uri = @trim($uri, '/'); // Keep details. $this->baseUri = $baseUri; $this->uri = $uri; }
/** * Logger constructor accepts a service name to associate with the logger. In * logging messages the service name will be shown for verbosity's sake. * * @param string $serviceName to associate with the logger */ public function __construct($serviceName) { $serviceName = @trim($serviceName); Assert::that(['condition' => $serviceName, 'message' => 'The service name cannot be empty', 'type' => Error::TYPE_ARGUMENT]); $this->serviceName = $serviceName; }
/** * Resizes (down-sizing only) the specified image to the maximum boundary set * by the specified dimension. If either dimension is set to 0, its value will * be automatically calculated using the other value, thus maintaining the * aspect ratio. * * @param \Fine47\ImageMan\Prototype $image to resize * @param int $targetWidth value for resizing * @param int $targetHeight value for resizing * @return \Fine47\ImageMan\Prototype resized image */ public static function resize(ImageMan\Prototype $image, $targetWidth = 0, $targetHeight = 0) { // Make sure that arguments are valid. $targetWidth = @intval($targetWidth); $targetHeight = @intval($targetHeight); Assert::that(['condition' => $targetWidth || $targetHeight, 'message' => 'Trying to resize an image to an invalid dimension', 'type' => Error::TYPE_ARGUMENT]); // Shortcut pointers. $imageWidth = $image->getWidth(); $imageHeight = $image->getHeight(); // If image is landscape, flip the target dimension. if ($imageHeight < $imageWidth) { $savedValue = $targetWidth; $targetWidth = $targetHeight; $targetHeight = $savedValue; unset($savedValue); } // If the target dimension is negative, return the original. if (0 > $targetWidth || 0 > $targetHeight) { // Make the target resolution exactly the same as the image's. // This will effectively bypass the resizing process. $targetWidth = $imageWidth; $targetHeight = $imageHeight; } else { if (1 > $targetWidth) { // Adjust target width since it's missing. $targetWidth = ceil($targetHeight * $imageWidth / $imageHeight); } else { if (1 > $targetHeight) { // Adjust target height since it's missing. $targetHeight = ceil($targetWidth * $imageHeight / $imageWidth); } } } // Resample to smaller size when original is larger than that. if ($targetWidth < $imageWidth || $targetHeight < $imageHeight) { // Calculate the scaling between widths and heights. $scale = min($targetWidth / $imageWidth, $targetHeight / $imageHeight); // Scale can be maximum 1. if (1 < $scale) { $scale = 1; } // Calculate maximum resize dimension. $resizeWidth = round($imageWidth * $scale); $resizeHeight = round($imageHeight * $scale); // Create a new empty image. $resized = self::newImage($image, $resizeWidth, $resizeHeight); // Resize the image. if (imagecopyresampled($resized->getResource(), $image->getResource(), 0, 0, 0, 0, $resizeWidth, $resizeHeight, $imageWidth, $imageHeight)) { return $resized; } else { $resized->gc(); $resized = null; Assert::raise(['message' => 'Unable to resize the image to [%dx%d]', 'args' => [$resizeWidth, $resizeHeight], 'type' => Error::TYPE_IMAGE]); } } // In all other cases, just return the original image. return $image; }
/** * Executes the specified query and returns the response. * * @param \Fine47\MicroRouter\Interfaces\Query $query to execute * @return \Fine47\MicroRouter\Interfaces\Response response of the query */ public function execute(Interfaces\Query $query) { // Get the action of this query. $action = $this->getRouter()->resolve($this, $query); // Make sure the action is valid. Assert::that(['condition' => $action, 'message' => 'Query URI cannot be resolved', 'type' => Error::TYPE_PARSE, 'magic' => 0x733f]); // Get list of filters for this action. $filters = $this->getActionFilters($action); // Are there any filters? if ($filters) { // Start running the onQuery() callbacks for the filters. $this->onQueryImpl($query, $action, $filters); // If the action is secured, apply security filtering. if ($action->isSecured()) { $this->onSecuredImpl($query, $action, $filters); } } // Execute the action and get a response. $response = $action->execute($this, $query); // A response MUST be produced by the action (otherwise, the action should // throw an exception.) Assert::that(['condition' => $response, 'message' => 'Response for this action cannot be empty', 'type' => Error::TYPE_PARSE, 'magic' => 0x5f31]); // Run onResponse callbacks as well. if ($filters) { // Start running the onResponse() callbacks for the filters. $this->onResponseImpl($response, $action, $filters); } return $response; }
/** * @internal auxiliary method to raise an error */ private function raisePossibleError($magic) { if ($this->dbc->errno) { $errorMsg = trim($this->dbc->error); if (!$errorMsg) { $errorMsg = 'Unknown database error detected.'; } Assert::that(['condition' => false, 'message' => $errorMsg, 'code' => $this->dbc->errno, 'type' => Error::TYPE_DATABASE, 'magic' => $magic]); } }
/** * Checks whether the specified value is a boolean. * * @param string $name of the parameter to check * @param array $value to check */ protected function checkIfBoolean($name, &$value) { // Make sure this is a float. Assert::that(['condition' => is_bool($value), 'message' => 'The mandatory field [%s] must be a boolean', 'args' => [$name], 'type' => Error::TYPE_INPUT]); }
/** * @see \Fine47\MicroRouter\Responses\Http::appendImpl() */ protected function appendImpl($body) { // Ensure that the body is an array. Assert::that(['condition' => is_array($body), 'message' => 'JSON response body must be an array', 'type' => Error::TYPE_ARGUMENT, 'magic' => 0x6722]); // Append new body recursively to the existing body. $this->arrayMergeImpl($this->body, $body); }