/** * Virtual properties like "length". * * @param string $property * * @return mixed */ public function __get($property) { if ($property == 'length') { return mb_strlen($this->text, 'UTF-8'); } $properties = \Sledgehammer\reflect_properties($this); $properties['public']['length'] = -1; \Sledgehammer\warning('Property: "' . $property . '" doesn\'t exist in a "' . get_class($this) . '" object.', \Sledgehammer\build_properties_hint($properties)); }
/** * Return credentials or false and send login headers. * * @return array|false */ public function authenticate() { if (isset($_SERVER['PHP_AUTH_USER'])) { // Is er een gebruikersnaam bekend? if (call_user_func($this->validation, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) { return array('username' => $_SERVER['PHP_AUTH_USER'], 'password' => $_SERVER['PHP_AUTH_PW']); } } if (headers_sent()) { \Sledgehammer\warning('Unable show login dialog, HTTP headers already sent'); return false; } $this->logout(); return false; }
/** * @param string $template * @param array $variables * @param array $headers */ public function __construct($template, $variables = array(), $headers = array()) { $this->variables = $variables; $this->headers = $headers; if (file_exists($template)) { // file found? $this->template = $template; } elseif (substr($template, 0, 1) !== '/') { // A relative path? foreach (static::$includePaths as $folder) { if (file_exists($folder . $template)) { // file found? $this->template = $folder . $template; break; } } } if ($this->template === null) { \Sledgehammer\warning('Template: "' . $template . '" not found', ['includePaths' => static::$includePaths]); $this->template = $template; } }
/** * CDATA & Inline DTD tags. * * @link http://nl.wikipedia.org/wiki/Document_Type_Definition#Voorbeeld_2 */ public function parseDTDTag() { if ($this->substr(0, 2) !== '<!') { throw new \Exception('parseDTDTag() saninty check failed'); } // @link http://en.wikipedia.org/wiki/CDATA#CDATA_sections_in_XML if ($this->substr(0, 9) == '<![CDATA[') { $this->buildToken($this->position + 8); $pos = $this->strpos(']]>'); if ($pos === false) { $this->warning('CDATA not terminated'); $this->buildLastToken('T_CDATA'); return; } if ($this->position == $pos) { \Sledgehammer\warning('Empty CDATA'); // Required? } else { $this->buildToken($pos - 1, 'T_CDATA'); } $this->buildToken($this->position + 2); $this->state = 'CONTENT'; return; } $this->buildToken($this->position + 1); $pos = $this->firstOccurrance(array_merge(array('[', '>'), $this->wsArray)); if ($pos === false) { $this->warning('Inline DTD tag not terminated'); $this->buildLastToken('T_DTD_ENTITY'); return; } if ($pos == $this->position) { $this->warning(' No DTD Entity defined'); } else { $this->buildToken($pos - 1, 'T_DTD_ENTITY'); } $this->parseDTDAttributes('OPEN'); }
/** * Fetch a single row. * * @param string $statement The SQL query * @param bool $allow_empty_results true: Suppress the notice when no record is found. * * @return array|false */ public function fetchRow($statement, $allow_empty_results = false) { $result = $this->query($statement); if ($result == false) { // Foutieve query return false; } elseif ($result->columnCount() == 0) { // UPDATE, INSERT query \Sledgehammer\warning('Resultset has no columns, expecting 1 or more columns'); return false; } $results = $result->fetchAll(); $count = count($results); if ($count == 1) { return $results[0]; } if (count($results) > 1) { \Sledgehammer\notice('Unexpected ' . count($results) . ' rows, expecting 1 row'); } elseif (!$allow_empty_results) { \Sledgehammer\notice('Row not found'); } return false; }
/** * Reports the error/exception to the ErrorHandler and returns the error as Json object. * The javascript client should detect and report the error to the user: * if (result.success !== true) { alert(result.error); }. * * @param string|Exception $error The error message or Exception * @param int $http The HTTP status code (defaults to 400 Bad Request) * * @return Json */ public static function error($error, $http = 400) { if (headers_sent() === false && DebugR::isEnabled()) { ErrorHandler::instance()->html = false; } if ($error instanceof Exception) { \Sledgehammer\report_exception($error); $error = $error->getMessage(); } else { \Sledgehammer\warning($error); } return new self(array('success' => false, 'error' => $error), array('http' => array('Status' => $http . ' ' . Framework::$statusCodes[$http], 'Content-Type' => ErrorHandler::instance()->html ? 'text/html; charset=utf-8' : 'application/json'))); }
/** * Report that $property doesn't exist and set the property to the given $value. * * @param string $property * @param mixed $value */ public function __set($property, $value) { \Sledgehammer\warning('Property "' . $property . '" doesn\'t exist in a ' . get_class($this) . ' object', \Sledgehammer\build_properties_hint(\Sledgehammer\reflect_properties($this))); $this->{$property} = $value; // Add the property to the object. (PHP's default behavior) }
/** * Access CURLINFO_* info as properties. * * @param string $property * * @return mixed */ public function __get($property) { $const = 'CURLINFO_' . strtoupper($property); if (defined($const)) { $option = eval('return ' . $const . ';'); $this->waitForCompletion(); return curl_getinfo($this->handle, $option); } $properties = \Sledgehammer\reflect_properties($this); $properties['public'] = array_merge($properties['public'], curl_getinfo($this->handle)); \Sledgehammer\warning('Property "' . $property . '" doesn\'t exist in a ' . get_class($this) . ' object', \Sledgehammer\build_properties_hint($properties)); }
/** * Return a subsection of the collection based on the conditions. * * Convert the $conditions to SQL object when appropriate. * * auto converts * ['x_id' => null] to "x_id IS NULL" * ['x_id !=' => null] to "x_id IS NOT NULL" * 'hits' => 0] to "hits = '0'" (Because in mysql '' = 0 evaluates to true, '' = '0' to false) * * @param array $conditions * * @return Collection */ public function where($conditions) { if ($this->data !== null || is_string($this->sql) || is_object($conditions) && is_callable($conditions) || $this->sql->limit !== false || $this->sql->offset != 0) { return parent::where($conditions); } $db = Connection::instance($this->dbLink); $sql = $this->sql; $logicalOperator = \Sledgehammer\extract_logical_operator($conditions); if ($logicalOperator === false) { if (count($conditions) > 1) { \Sledgehammer\notice('Conditions with multiple conditions require a logical operator.', "Example: array('AND', 'x' => 1, 'y' => 5)"); } $logicalOperator = 'AND'; } else { unset($conditions[0]); } if ($logicalOperator === 'AND') { $method = 'andWhere'; } elseif ($logicalOperator === 'OR') { $method = 'orWhere'; } else { throw new Exception('Unsupported logical operator "' . $logicalOperator . '", expecting "AND" or "OR"'); } // The result are rows(fetch_assoc arrays), all conditions must be columnnames (or invalid) foreach ($conditions as $path => $value) { if (preg_match('/^(.*) (' . \Sledgehammer\COMPARE_OPERATORS . ')$/', $path, $matches)) { $column = $this->convertPathToColumn($matches[1]); $operator = $matches[2]; } else { $column = $this->convertPathToColumn($path); $operator = '=='; } if ($column === false) { // Converting to path failed? \Sledgehammer\array_key_unshift($conditions, 0, $logicalOperator); return parent::where($conditions); } if ($value === null) { switch ($operator) { case '==': $operator = 'IS'; $expectation = 'NULL'; break; case '!=': $operator = 'IS NOT '; $expectation = 'NULL'; break; case '>': case '<': case '>=': case '<=': $expectation = "''"; break; default: \Sledgehammer\warning('Unknown behavior for NULL values with operator "' . $operator . '"'); $expectation = $db->quote($expectation); break; } $sql = $sql->{$method}($column . ' ' . $operator . ' ' . $expectation); } else { if ($operator === '!=') { $sql = $sql->{$method}('(' . $column . ' != ' . $db->quote($value, PDO::PARAM_STR) . ' OR ' . $column . ' IS NULL)'); } elseif ($operator === 'IN') { if ((is_array($value) || $value instanceof Traversable) === false) { \Sledgehammer\notice('Operator IN expects an array or Traversable', $value); $value = explode(',', $value); } $quoted = []; foreach ($value as $val) { $quoted[] = $this->quote($db, $column, $val); } $sql = $sql->{$method}($column . ' ' . $operator . ' (' . implode(', ', $quoted) . ')'); } else { if ($operator === '==') { $operator = '='; } $sql = $sql->{$method}($column . ' ' . $operator . ' ' . $this->quote($db, $column, $value)); } } } return new self($sql, $this->dbLink); }
/** * Release the lock for this cached entry. */ private function apc_release() { if (apc_delete($this->_guid . '.lock') == false) { \Sledgehammer\warning('apc_delete() failed, was already released?'); } }
/** * Remove a callback from an event. * * @param string $event * @param string $identifier */ public function off($event, $identifier) { if ($this->hasEvent($event) === false) { \Sledgehammer\warning('Event: "' . $event . '" not registered', 'Available events: ' . \Sledgehammer\quoted_human_implode(', ', array_keys($this->events))); return false; } if (empty($this->events[$event][$identifier])) { \Sledgehammer\warning('Identifier: "' . $identifier . '" not found in listeners for event: "' . $event . '"', 'Available identifiers: ' . \Sledgehammer\quoted_human_implode(', ', array_keys($this->events[$event]))); return false; } unset($this->events[$event][$identifier]); return true; }
/** * Build a path string from a (mutated) parsed path. * * @param array $parsedPath Output from PropertyPath::parse($path) * * @return string path */ public static function assemble($parsedPath) { $path = ''; // @todo Excape values $tokens = array_values($parsedPath); // Force to first $index to 0 foreach ($tokens as $index => $token) { $value = self::escape($token[1]); switch ($token[0]) { case self::TYPE_ANY: if ($index != 0) { $path .= '.'; } $path .= $value; break; case self::TYPE_PROPERTY: $path .= '->' . $value; break; case self::TYPE_ELEMENT: $path .= '[' . $value . ']'; break; case self::TYPE_METHOD: $path .= $value . '()'; break; case self::TYPE_OPTIONAL: if ($index != 0) { $path .= '.'; } $path .= $value . '?'; break; case self::TYPE_OPTIONAL_PROPERTY: $path .= '->' . $value . '?'; break; case self::TYPE_OPTIONAL_ELEMENT: $path .= '[' . $value . '?]'; break; default: \Sledgehammer\warning('Unsupported token', $token); } } return $path; }
/** * Import a class into the required namespace. * * @param string $definition Fully qualified class/interface name * * @return bool */ private function resolveNamespace($definition) { if (strpos($definition, '\\') === false) { // Definition in the global namespace? if ($this->isLast() === false) { return false; // Allow the other autoloaders to define the definition. } $extends = false; $class = $definition; foreach (array_keys($this->definitions) as $definition) { $pos = strrpos($definition, '\\'); if ($pos !== false && substr($definition, $pos + 1) === $class) { $extends = $definition; $targetNamespace = ''; $this->define($definition); break; } } if ($extends === false) { // No matching classname found? return false; } } else { $namespaces = explode('\\', $definition); $class = array_pop($namespaces); $targetNamespace = implode('\\', $namespaces); if (count($namespaces) === 1 && $namespaces[0] == 'Sledgehammer') { // Pre 2016 notation? $extends = 'Sledgehammer\\Core\\' . $class; } else { // Try stripping 1 namespace (todo multiple) array_pop($namespaces); // een namespace laag hoger $extends = implode('\\', $namespaces); if ($extends == '') { $extends = $class; } else { $extends .= '\\' . $class; } } if (isset($this->definitions[$extends])) { $this->define($extends); } } $php = 'namespace ' . $targetNamespace . " {\n\t"; if (class_exists($extends, false)) { $php .= 'class ' . $class; $reflection = new ReflectionClass($extends); if (count($reflection->getMethods(ReflectionMethod::IS_ABSTRACT)) !== 0) { \Sledgehammer\notice('Cant\' import "' . $class . '" into namespace "' . $targetNamespace . '" ("' . $extends . '" contains abstract methods)'); return false; } } elseif (interface_exists($class, false)) { $php .= 'interface ' . $class; } else { return false; } if ($targetNamespace === '') { $namespaces = explode('\\', $definition); array_pop($namespaces); \Sledgehammer\warning('Definition "' . $class . '" not found, importing "' . $definition . '" into the the global namespace', 'Change the classname or add "namespace ' . implode('\\', $namespaces) . ';" or "use \\' . $definition . ';" to the beginning of the php file"'); } elseif (error_reporting() == (error_reporting() | E_STRICT)) { // Strict mode \Sledgehammer\notice('Importing "' . $extends . '" into namespace "' . $targetNamespace . '"', 'use ' . $extends . ';'); } $php .= ' extends \\' . $extends . " {}\n}"; eval($php); return true; }