From 44beb7ed3210f911880525f9eda919ca65f9bf31 Mon Sep 17 00:00:00 2001 From: Guilherme Nascimento Date: Sun, 29 Dec 2019 03:25:58 -0300 Subject: [PATCH] Version 0.5.1 :space_invader: - Fixed preview in Debug::source() - Debug::source() returns only files backtrace (ignore closures and etc) - Debug::source() returns more details - Improved offset and max in File::portion() and File::lines() - Removed unnecessary LOCK and improved performance in Storage::temp() - Improved Dom\Document::fromArray() (`Helper::seq` is unnecessary now) - New CSS selector (non-standard) to Document::query() (and `new Dom\Selector` class) - Searches for file that "EVAL" fails (`Debug::evalFileLocation()`) - Search for the file where the `eval()'d` failed (`Debug::evalFileLocation()`) - Improved PHPDoc --- src/Experimental/Debug.php | 143 ++++++++++++++++-------------- src/Experimental/Dir.php | 8 +- src/Experimental/Dom/Document.php | 36 +++++--- src/Experimental/Dom/Selector.php | 3 +- src/Experimental/File.php | 10 +-- src/Experimental/Http/Request.php | 2 + src/Experimental/Session.php | 2 + src/Inphinit/Packages.php | 2 + src/Inphinit/Storage.php | 35 ++++---- 9 files changed, 134 insertions(+), 107 deletions(-) diff --git a/src/Experimental/Debug.php b/src/Experimental/Debug.php index 547cb83..b6fc87e 100644 --- a/src/Experimental/Debug.php +++ b/src/Experimental/Debug.php @@ -115,7 +115,7 @@ public static function renderClasses() * * @param string $type * @param string $view - * + * @throws \Inphinit\Experimental\Exception * @return void */ public static function view($type, $view) @@ -155,55 +155,6 @@ public static function view($type, $view) } } - private static function details($type, $message, $file, $line) - { - $match = array(); - $oFile = $file; - - if (preg_match('#called in ([\s\S]+?) on line (\d+)#', $message, $match)) { - $file = $match[1]; - $line = (int) $match[2]; - } - - if (preg_match('#(.*?)\((\d+)\) : eval\(\)\'d code$#', trim($file), $match)) { - $oFile = $match[1] . ' : eval():' . $line; - $file = $match[1]; - $line = (int) $match[2]; - } - - switch ($type) { - case E_PARSE: - $message = 'Parse error: ' . $message; - break; - - case E_DEPRECATED: - $message = 'Deprecated: ' . $message; - break; - - case E_ERROR: - case E_USER_ERROR: - $message = 'Fatal error: ' . $message; - break; - - case E_WARNING: - case E_USER_WARNING: - $message = 'Warning: ' . $message; - break; - - case E_NOTICE: - case E_USER_NOTICE: - $message = 'Notice: ' . $message; - break; - } - - return array( - 'message' => $message, - 'file' => $oFile, - 'line' => $line, - 'source' => $line > -1 ? self::source($file, $line) : null - ); - } - /** * Get memory usage and you can also use it to calculate runtime. * @@ -253,7 +204,7 @@ public static function source($file, $line) if ($line <= 0 || is_file($file) === false) { return null; } elseif ($line > 5) { - $init = $line - 5; + $init = $line - 6; $end = $line + 5; $breakpoint = 6; } else { @@ -262,17 +213,20 @@ public static function source($file, $line) $breakpoint = $line; } + $preview = preg_split('#\r\n|\n#', File::lines($file, $init, $end)); + + if (count($preview) !== $breakpoint && trim(end($preview)) === '') { + array_pop($preview); + } + return array( 'breakpoint' => $breakpoint, - 'preview' => preg_split( - '#\r\n|\n#', - trim(File::portion($file, $init, $end, true), "\r\n") - ) + 'preview' => $preview ); } /** - * Get caller + * Get backtrace php scripts * * @param int $level * @return array|null @@ -281,23 +235,23 @@ public static function caller($level = 0) { $trace = debug_backtrace(0); + foreach ($trace as $key => &$value) { + if (isset($value['file']) === false) { + unset($trace[$key]); + } else { + self::evalFileLocation($value['file'], $value['line']); + } + } + + $trace = array_values($trace); + if ($level < 0) { return $trace; } elseif (empty($trace[$level])) { return null; - } elseif (empty($trace[$level]['file'])) { - $level = 1; } - $file = $trace[$level]['file']; - $line = $trace[$level]['line']; - - $trace = null; - - return array( - 'file' => $file, - 'line' => $line - ); + return $trace = $trace[$level]; } /** @@ -338,4 +292,59 @@ private static function render($view, $data) View::render($view, $data); } + + private static function details($type, $message, $file, $line) + { + $match = array(); + //$oFile = $file; + + if (preg_match('#called in ([\s\S]+?) on line (\d+)#', $message, $match)) { + $file = $match[1]; + $line = (int) $match[2]; + } + + self::evalFileLocation($file, $line); + + switch ($type) { + case E_PARSE: + $message = 'Parse error: ' . $message; + break; + + case E_DEPRECATED: + case E_USER_DEPRECATED: + $message = 'Deprecated: ' . $message; + break; + + case E_ERROR: + case E_USER_ERROR: + case E_RECOVERABLE_ERROR: + $message = 'Fatal error: ' . $message; + break; + + case E_WARNING: + case E_USER_WARNING: + $message = 'Warning: ' . $message; + break; + + case E_NOTICE: + case E_USER_NOTICE: + $message = 'Notice: ' . $message; + break; + } + + return array( + 'message' => $message, + 'file' => $file, + 'line' => $line, + 'source' => $line > -1 ? self::source($file, $line) : null + ); + } + + private static function evalFileLocation(&$file, &$line) + { + if (preg_match('#(.*?)\((\d+)\) : eval\(\)\'d code#', $file, $match)) { + $file = $match[1]; + $line = (int) $match[2]; + } + } } diff --git a/src/Experimental/Dir.php b/src/Experimental/Dir.php index 6d3e47b..7513405 100644 --- a/src/Experimental/Dir.php +++ b/src/Experimental/Dir.php @@ -34,14 +34,14 @@ public function __construct($path) $handle = opendir($path); if ($handle) { - while (($name = readdir($handle)) !== false) { - if ($name !== '.' && $name !== '..') { - $current = $path . $name; + while ($file = readdir($handle)) { + if ($file !== '.' && $file !== '..') { + $current = $path . $file; $data[] = (object) array( 'type' => filetype($current), 'path' => $current, - 'name' => $name + 'name' => $file ); } } diff --git a/src/Experimental/Dom/Document.php b/src/Experimental/Dom/Document.php index 242b0b7..31f33ad 100644 --- a/src/Experimental/Dom/Document.php +++ b/src/Experimental/Dom/Document.php @@ -83,7 +83,7 @@ public function reporting() * Convert a array in node elements * * @param array|\Traversable $data - * @throws \Inphinit\Experimental\Exception + * @throws \Inphinit\Experimental\Dom\DomException * @return void */ public function fromArray(array $data) @@ -92,8 +92,12 @@ public function fromArray(array $data) throw new DomException('Array is empty', 2); } elseif (count($data) > 1) { throw new DomException('Root array accepts only a key', 2); - } elseif (Helper::seq($data)) { - throw new DomException('Document accpet only a node', 2); + } + + $root = key($data); + + if (self::validTag($root) === false) { + throw new DomException('Invalid root <' . $root . '> tag', 2); } if ($this->documentElement) { @@ -102,7 +106,7 @@ public function fromArray(array $data) $this->enableRestoreInternal(true); - $this->generate($this, $data); + $this->generate($this, $data, 2); $this->raise($this->exceptionlevel); @@ -132,7 +136,7 @@ public function toJson($format = Document::MINIMAL, $options = 0) * Convert DOM to Array * * @param int $type - * @throws \Inphinit\Experimental\Exception + * @throws \Inphinit\Experimental\Dom\DomException * @return array */ public function toArray($type = Document::SIMPLE) @@ -186,7 +190,7 @@ public function __toString() * * @param string $path * @param int $format Support XML, HTML, and JSON - * @throws \Inphinit\Experimental\Exception + * @throws \Inphinit\Experimental\Dom\DomException * @return void */ public function save($path, $format = Document::XML) @@ -220,7 +224,6 @@ public function save($path, $format = Document::XML) * Get namespace attributes from root element or specific element * * @param \DOMElement $element - * @throws \Inphinit\Experimental\Exception * @return void */ public function getNamespaces(\DOMElement $element = null) @@ -387,34 +390,43 @@ private function raise($debuglvl) \libxml_clear_errors(); } - private function generate(\DOMNode $node, $data) + private function generate(\DOMNode $node, $data, $errorLevel) { if (is_array($data) === false) { $node->textContent = $data; return; } + $nextLevel = $errorLevel + 1; + foreach ($data as $key => $value) { if ($key === '@comments') { continue; } elseif ($key === '@contents') { - $this->generate($node, $value); + $this->generate($node, $value, $nextLevel); } elseif ($key === '@attributes') { $this->attrs($node, $value); - } elseif (preg_match('#^([a-z]|[a-z][\w:])+$#i', $key)) { + } elseif (self::validTag($key)) { if (Helper::seq($value)) { foreach ($value as $subvalue) { - $this->generate($node, array($key => $subvalue)); + $this->generate($node, array($key => $subvalue), $nextLevel); } } elseif (is_array($value)) { - $this->generate($this->add($key, '', $node), $value); + $this->generate($this->add($key, '', $node), $value, $nextLevel); } else { $this->add($key, $value, $node); } + } else { + throw new DomException('Invalid root <' . $key . '> tag', $nextLevel); } } } + private function validTag($tagName) + { + return preg_match('#^([a-z_](\w+|)|[a-z_](\w+|):[a-z_](\w+|))$#i', $tagName) > 0; + } + private function add($name, $value, \DOMNode $node) { $newdom = $this->createElement($name, $value); diff --git a/src/Experimental/Dom/Selector.php b/src/Experimental/Dom/Selector.php index ffc7c7d..da343d1 100644 --- a/src/Experimental/Dom/Selector.php +++ b/src/Experimental/Dom/Selector.php @@ -44,7 +44,8 @@ class Selector extends \DOMXPath array( '/\[(@\w+|lower-case\(@\w+\))\~=(.*?)\]/', '[contains(concat(" ",\\1," "),concat(" ",\\2," "))]' ), array( '/\[(@\w+|lower-case\(@\w+\))\|=(.*?)\]/', '[starts-with(concat(\\1,"-"),concat(\\2,"-"))]' ), array( '/\[(@\w+|lower-case\(@\w+\))\$=(.*?)\]/', '[substring(\\1,string-length(\\1)-2)=\\2]' ), - array( '/\:contains\((.*?)\)/i', '[contains(.,\\1)]' ) + array( '/\:contains\((.*?)\)/i', '[contains(.,\\1)]' ), + array( '/\:contains-child\((.*?)\)/i', '[text()[contains(.,\\1)]]' ) ); /** diff --git a/src/Experimental/File.php b/src/Experimental/File.php index 0f958e5..02447d1 100644 --- a/src/Experimental/File.php +++ b/src/Experimental/File.php @@ -32,21 +32,21 @@ public static function portion($path, $offset = 0, $max = 1024) * * @param string $path * @param int $offset - * @param int $maxLines + * @param int $maxLine * @throws \Inphinit\Experimental\Exception * @return string */ - public static function lines($path, $offset = 0, $maxLines = 1024) + public static function lines($path, $offset = 0, $maxLine = 32) { - $i = 1; + $i = 0; $output = ''; $handle = fopen($path, 'rb'); - while (false === feof($handle) && $i <= $end) { + while (false === feof($handle) && $i < $maxLine) { $data = fgets($handle); - if ($i >= $init) { + if ($i >= $offset) { $output .= $data; } diff --git a/src/Experimental/Http/Request.php b/src/Experimental/Http/Request.php index 5e50f90..03b80a3 100644 --- a/src/Experimental/Http/Request.php +++ b/src/Experimental/Http/Request.php @@ -22,6 +22,7 @@ class Request extends \Inphinit\Http\Request * Get a value input handler * * @param bool $array + * @throws \Inphinit\Experimental\Exception * @return array|stdClass|null */ public static function json($array = false) @@ -55,6 +56,7 @@ public static function json($array = false) /** * Get a value input handler * + * @throws \Inphinit\Experimental\Dom\DomException * @return \Inphinit\Experimental\Dom\Document */ public static function xml() diff --git a/src/Experimental/Session.php b/src/Experimental/Session.php index 5eee934..824724b 100644 --- a/src/Experimental/Session.php +++ b/src/Experimental/Session.php @@ -169,6 +169,7 @@ public function regenerate($id = null, $trydeleteold = false) /** * Set cookie * + * @throws \Inphinit\Experimental\Exception * @return void */ private function cookie() @@ -284,6 +285,7 @@ public function __get($name) * * @param string $name * @param mixed $value + * @throws \Inphinit\Experimental\Exception * @return void */ public function __set($name, $value) diff --git a/src/Inphinit/Packages.php b/src/Inphinit/Packages.php index fb2f650..dabfa09 100644 --- a/src/Inphinit/Packages.php +++ b/src/Inphinit/Packages.php @@ -23,6 +23,7 @@ class Packages implements \IteratorAggregate * Create a `Inphinit\Packages` instance. * * @param string $path Setup composer path, like `./vendor/composer` + * @throws \InvalidArgumentException * @return void */ public function __construct($path) @@ -149,6 +150,7 @@ public function psr4() * Save imported packages path to file in PHP format * * @param string $path File to save packages paths, eg. `/foo/namespaces.php` + * @throws \InvalidArgumentException * @return bool */ public function save($path) diff --git a/src/Inphinit/Storage.php b/src/Inphinit/Storage.php index fc156e4..6371a17 100644 --- a/src/Inphinit/Storage.php +++ b/src/Inphinit/Storage.php @@ -34,12 +34,13 @@ public static function resolve($path) } $path = Uri::canonpath($path); + $currentPath = self::path(); - if ($path . '/' === self::path() || strpos($path, self::path()) === 0) { + if ($path . '/' === $currentPath || strpos($path, $currentPath) === 0) { return $path; } - return self::path() . $path; + return $currentPath . $path; } /** @@ -53,7 +54,7 @@ public static function autoclean($path, $time = -1) { $path = self::resolve($path); - if ($path !== false && is_dir($path) && ($dh = opendir($path))) { + if ($path !== false && is_dir($path) && ($handle = opendir($path))) { if ($time < 0) { $time = App::env('appdata_expires'); } @@ -61,7 +62,7 @@ public static function autoclean($path, $time = -1) $expires = REQUEST_TIME - $time; $path .= '/'; - while (false !== ($file = readdir($dh))) { + while ($file = readdir($handle)) { $current = $path . $file; if (is_file($current) && filemtime($current) < $expires) { @@ -69,9 +70,7 @@ public static function autoclean($path, $time = -1) } } - closedir($dh); - - $dh = null; + closedir($handle); } } @@ -91,21 +90,21 @@ public static function temp($data = null, $dir = 'tmp', $prefix = '~', $sulfix = return false; } - $path = $fullpath . '/' . $prefix . mt_rand(1, 1000) . $sulfix; + $rand = mt_rand(); - if ($handler = fopen($path, 'x')) { - if (!$data) { - return $path; - } elseif (flock($handler, LOCK_EX)) { - fwrite($handler, $data); - flock($handler, LOCK_UN); + while (true) { + $path = $fullpath . '/' . $prefix . $rand . $sulfix; + + if ($handle = fopen($path, 'x')) { + if ($data !== null) { + fwrite($handle, $data); + } + fclose($handle); return $path; - } else { - return false; } - } else { - return self::temp($data, $dir, $prefix, $sulfix); + + ++$rand; } }