0, 'timeout' => 10, 'sslverifypeer' => false, ]; protected $validLocationUrlCodes = [301, 302, 200]; protected $warningLocationUrlCodes = [301]; protected $index; protected $line; protected $columns = [ 'line' => [ 'title' => 'Line', 'width' => 6, 'align' => 'center', ], 'testType' => [ 'title' => 'Test Type', 'width' => 15, ], 'url' => [ 'title' => 'URLs', 'width' => 122, ], 'message' => [ 'title' => 'Message', 'width' => 42, ], 'status' => [ 'title' => 'Status', 'width' => 9, ], ]; /** * @var ConsoleColorText */ protected $text; protected $_user; protected $_password; protected $format = self::FORMAT_CONSOLE; protected $noSuccess = false; protected $filterLines; function __construct($options = []) { $this->client = new Client(null, array_merge($this->clientDefaultOptions, $options)); $this->client->getRequest()->setMethod(Request::METHOD_HEAD); $this->text = new ConsoleColorText(); } public function getFormat() { return $this->format; } public function setFormat($format) { $this->format = $format; return $this; } /** * @return boolean */ public function isNoSuccess() { return $this->noSuccess; } /** * @param boolean $noSuccess * @return $this */ public function setNoSuccess($noSuccess) { $this->noSuccess = $noSuccess; return $this; } /** * @return mixed */ public function getFilterLines() { return $this->filterLines; } /** * @param mixed $filterLines * @return $this */ public function setFilterLines($filterLines) { $this->filterLines = $this->parseFilterLines($filterLines); return $this; } protected function parseFilterLines($filterLines) { $matches = []; if (!preg_match('/^(\d+)(\:)?(\d+)?$/', $filterLines, $matches)) { return null; } $start = $matches[1]; $end = isset($matches[3]) ? $matches[3] : null; return [$start, isset($matches[2]) ? $end : $start]; } public function head($url) { $this->_initCredentials(); return $this->client->setUri($url)->send(); } public function validateRedirect($sourceUrl, $destinationUrl, array $flags = []) { if (empty($flags['R'])) { $this->logError(self::TYPE_DST_URL, $destinationUrl, 'R flag is undefined'); return false; } $response = $this->head($sourceUrl); // Validate Source URL Redirect Code if ($flags['R'] != ($code = $response->getStatusCode())) { $this->logError( self::TYPE_SRC_URL, $this->_formatUrl($sourceUrl), 'HTTP ' . $code . ' (' . $flags['R'] . ' expected)' ); return false; } $this->logSuccess(self::TYPE_SRC_URL, $this->_formatUrl($sourceUrl), 'HTTP ' . $code); if ($this->areUrlEqual($sourceUrl, $destinationUrl)) { $this->logError(self::TYPE_DST_URL, $destinationUrl, 'infinite loop'); return false; } /** @var $location Zend\Http\Header\Location */ if (!($location = $response->getHeaders()->get('Location')) || !($locationUrl = $location->getFieldValue())) { $this->logError(self::TYPE_SRC_URL, $this->_formatUrl($sourceUrl), '"Location" header is undefined'); return false; } // Validate Location $locationResponse = $this->head($locationUrl); if (!($isValidLocationCode = in_array($locationResponse->getStatusCode(), $this->validLocationUrlCodes))) { $this->logError( self::TYPE_DST_URL, ' --> ' . $this->_formatUrl($locationUrl), 'unexpected HTTP code ' . $locationResponse->getStatusCode() ); } else { $message = 'HTTP ' . $locationResponse->getStatusCode(); if (in_array($locationResponse->getStatusCode(), $this->warningLocationUrlCodes)) { $this->logWarning(self::TYPE_DST_URL, ' --> ' . $this->_formatUrl($locationUrl), $message); } else { $this->logSuccess(self::TYPE_DST_URL, ' --> ' . $this->_formatUrl($locationUrl), $message); } } if (!$this->areUrlEqual($locationUrl, $destinationUrl)) { $this->logError(self::TYPE_DST_URL_MATCH, ' --> ' . $this->_formatUrl($destinationUrl)); } else { $this->logSuccess(self::TYPE_DST_URL_MATCH, ' --> ' . $this->_formatUrl($destinationUrl)); } return true; } protected function logWarning($testType, $url, $message = null) { return $this->log($testType, $url, $this->_formatWarning($message), $this->_formatWarning(self::STATUS_WARNING)); } protected function logError($testType, $url, $message = null) { return $this->log($testType, $url, $this->_formatError($message), $this->_formatError(self::STATUS_FAILED)); } protected function logSuccess($testType, $url, $message = null) { if ($this->isNoSuccess()) { return $this; } return $this->log($testType, $url, $this->_formatSuccess($message), $this->_formatSuccess(self::STATUS_SUCCESS)); } protected function _formatError($text) { switch ($this->getFormat()) { case self::FORMAT_YOUTRACK: return '{color:red}' . $text . '{color}'; case self::FORMAT_CONSOLE: return $this->text->paint($text, 'red'); case self::FORMAT_HTML: return '' . htmlspecialchars($text) . ''; } return new Exception('Undefined Format: ' . $this->getFormat()); } protected function _formatWarning($text) { switch ($this->getFormat()) { case self::FORMAT_YOUTRACK: return '{color:orange}' . $text . '{color}'; case self::FORMAT_CONSOLE: return $this->text->paint($text, 'orange'); case self::FORMAT_HTML: return '' . htmlspecialchars($text) . ''; } return new Exception('Undefined Format: ' . $this->getFormat()); } protected function _formatSuccess($text) { switch ($this->getFormat()) { case self::FORMAT_YOUTRACK: return '{color:green}' . $text . '{color}'; case self::FORMAT_CONSOLE: return $this->text->paint($text, 'green'); case self::FORMAT_HTML: return '' . htmlspecialchars($text) . ''; } return new Exception('Undefined Format: ' . $this->getFormat()); } protected function areUrlEqual($locationUrl, $destinationUrl) { if ('?' == substr($destinationUrl, -1)) { $destinationUrl = substr($destinationUrl, 0, -1); } return rawurldecode($locationUrl) == rawurldecode($destinationUrl); } public function log($testType, $url, $message, $status) { $line = $this->line + 1; $values = compact('line', 'testType', 'url', 'message', 'status'); $columns = []; foreach ($this->columns as $name => $column) { $align = array_key_exists('align', $column) ? $column['align'] : null; $value = $values[$name]; switch ($this->getFormat()) { case self::FORMAT_YOUTRACK: case self::FORMAT_CONSOLE: $columns[] = $this->sprint($value, $column['width'], $align); break; case self::FORMAT_HTML: $columns[] = $value; break; default: return new Exception('Undefined Format: ' . $this->getFormat()); } } switch ($this->getFormat()) { case self::FORMAT_YOUTRACK: echo implode('||', $columns) . PHP_EOL; break; case self::FORMAT_CONSOLE: echo implode('|', $columns) . PHP_EOL; break; case self::FORMAT_HTML: echo '
' . implode(' | ', $columns) . ' |
---|