mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-07 18:14:35 +00:00
351 lines
9.4 KiB
PHP
351 lines
9.4 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Exception related to W3CFeedValidator object
|
|
*/
|
|
class W3CFeedValidatorException extends Exception
|
|
{
|
|
|
|
}
|
|
|
|
/**
|
|
* Use W3C API FEED VALIDATOR
|
|
* @see http://validator.w3.org/feed/docs/soap.html
|
|
*/
|
|
abstract class W3CFeedValidator
|
|
{
|
|
const VALIDATOR_ENDPOINT = "http://validator.w3.org/feed/check.cgi";
|
|
const OUTPOUT = "soap12";
|
|
const TIME_BETWEEN_REQUEST = 2;
|
|
|
|
public abstract function validate();
|
|
}
|
|
|
|
/**
|
|
* Use W3C API to valide your RSS FEED identified by an URL
|
|
* @see http://validator.w3.org/feed/docs/soap.html
|
|
*/
|
|
class W3CFeedUrlValidator extends W3CFeedValidator
|
|
{
|
|
/**
|
|
* The URL of the document to validate
|
|
* @var string
|
|
*/
|
|
private $url;
|
|
|
|
/**
|
|
* Constructor
|
|
* Init instance with a specified url which identify a XML to validate
|
|
* @param string $url
|
|
* @throws W3CFeedValidatorException if url is not valid
|
|
*/
|
|
public function __construct($url)
|
|
{
|
|
if ( ! $this->isValidUrl($url))
|
|
throw new W3CFeedValidatorException(sprintf("Invalid url %s", $url));
|
|
|
|
$this->url = $url;
|
|
}
|
|
|
|
/**
|
|
* Validate the xml feed located at the current url
|
|
* @param string $feed_url
|
|
* @return W3CFeedValidatorResponse
|
|
* @throws W3CFeedValidatorException if the request failed
|
|
*/
|
|
public function validate()
|
|
{
|
|
$url_validator = sprintf("%s?url=%s&output=%s", self::VALIDATOR_ENDPOINT, $this->url, self::OUTPOUT);
|
|
sleep(self::TIME_BETWEEN_REQUEST);
|
|
$response = @file_get_contents($url_validator);
|
|
if ( ! $response) {
|
|
throw new W3CFeedValidatorException("Unable to request W3C API");
|
|
}
|
|
|
|
return new W3CFeedValidatorResponse($response);
|
|
}
|
|
|
|
/**
|
|
* Check if an url is valid
|
|
* @param string $url
|
|
* @return boolean
|
|
*/
|
|
private function isValidUrl($url)
|
|
{
|
|
return filter_var($url, FILTER_VALIDATE_URL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @example
|
|
*
|
|
* try
|
|
* {
|
|
* $validator = new W3CFeedRawValidator($xml);
|
|
* $response = $validator->validate();
|
|
*
|
|
* if($response->isValid())
|
|
* {
|
|
* //do something
|
|
* }
|
|
*
|
|
* $validator = new W3CFeedUrlValidator($url);
|
|
* $response = $validator->validate();
|
|
*
|
|
* if($response->isValid())
|
|
* {
|
|
* //do something
|
|
* }
|
|
* }
|
|
* catch (W3CFeedValidatorException $e)
|
|
* {
|
|
* print "\n" . $e->getMessage();
|
|
* }
|
|
*
|
|
* Use W3C API to valide your RSS FEED
|
|
* @see http://validator.w3.org/feed/docs/soap.html
|
|
*/
|
|
class W3CFeedRawValidator extends W3CFeedValidator
|
|
{
|
|
/**
|
|
* The source of the document to validate
|
|
* @var string
|
|
*/
|
|
private $rawData;
|
|
|
|
/**
|
|
* Constructor
|
|
* Init instance which the specified data to validate
|
|
* @param string $rawData
|
|
*/
|
|
public function __construct($rawData)
|
|
{
|
|
$this->rawData = utf8_encode(trim($rawData));
|
|
}
|
|
|
|
/**
|
|
* Validate the rawData xml
|
|
* @param string $feed_url
|
|
* @return W3CFeedValidatorResponse
|
|
* @throws W3CFeedValidatorException if the request failed
|
|
*/
|
|
public function validate()
|
|
{
|
|
$context = stream_context_create([
|
|
'http' => [
|
|
'method' => 'POST',
|
|
'header' => 'Content-type: application/x-www-form-urlencoded',
|
|
'content' => http_build_query([
|
|
'rawdata' => $this->rawData,
|
|
'manual' => 1,
|
|
'output' => self::OUTPOUT]),
|
|
'timeout' => 5,
|
|
],
|
|
]);
|
|
sleep(self::TIME_BETWEEN_REQUEST);
|
|
$response = @file_get_contents(self::VALIDATOR_ENDPOINT, false, $context);
|
|
if ( ! $response) {
|
|
throw new W3CFeedValidatorException("Unable to request W3C API");
|
|
}
|
|
|
|
return new W3CFeedValidatorResponse($response);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An object that handle the W3C FEED VALIDATOR response
|
|
*/
|
|
class W3CFeedValidatorResponse
|
|
{
|
|
/**
|
|
* XML W3C response
|
|
* @var string
|
|
*/
|
|
private $xml;
|
|
|
|
/**
|
|
* @var DOMDocument
|
|
*/
|
|
private $DOMDocument;
|
|
|
|
/**
|
|
* @var DOMXPath
|
|
*/
|
|
private $DOMXpath;
|
|
|
|
/**
|
|
* Constructor
|
|
* Init instance with the W3C FEED VALIDATOR xml response
|
|
* @param string $xml
|
|
* @throws W3CFeedValidatorException if xml can't be loaded
|
|
*/
|
|
public function __construct($xml)
|
|
{
|
|
$this->DOMDocument = new DOMDocument();
|
|
if ( ! $this->DOMDocument->loadXML($xml)) {
|
|
throw new W3CFeedValidatorException("Unable to parse XML");
|
|
}
|
|
$this->DOMXpath = new DOMXPath($this->DOMDocument);
|
|
$this->DOMXpath->registerNamespace("env", "http://www.w3.org/2003/05/soap-envelope");
|
|
$this->DOMXpath->registerNamespace("m", "http://www.w3.org/2005/10/feed-validator");
|
|
|
|
$this->xml = $xml;
|
|
}
|
|
|
|
public function __toString()
|
|
{
|
|
$string = "";
|
|
foreach ($this->getErrors() as $error) {
|
|
$string .= "\nERROR\n";
|
|
foreach ($error as $name => $detail) {
|
|
$string .= $name . "=>" . $detail . "\n";
|
|
}
|
|
}
|
|
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Check if the XML is valid
|
|
* @return boolean
|
|
*/
|
|
public function isValid()
|
|
{
|
|
$xPathQuery = "/env:Envelope/env:Body/m:feedvalidationresponse/m:validity";
|
|
|
|
return $this->DOMXpath->query($xPathQuery)->item(0)->nodeValue !== "false";
|
|
}
|
|
|
|
/**
|
|
* Check for errors
|
|
* @return boolean
|
|
*/
|
|
public function hasError()
|
|
{
|
|
$xPathQuery = "/env:Envelope/env:Body/m:feedvalidationresponse/m:errors/m:errorcount";
|
|
|
|
return (int) $this->DOMXpath->query($xPathQuery)->item(0)->nodeValue !== 0;
|
|
}
|
|
|
|
/**
|
|
* check fro warnings
|
|
* @return boolean
|
|
*/
|
|
public function hasWarning()
|
|
{
|
|
$xPathQuery = "/env:Envelope/env:Body/m:feedvalidationresponse/m:warnings/m:warningcount";
|
|
|
|
return (int) $this->DOMXpath->query($xPathQuery)->item(0)->nodeValue !== 0;
|
|
}
|
|
|
|
/**
|
|
* Get an array with all warnings as follow
|
|
* array{
|
|
* 0 => array {
|
|
* array(10) {
|
|
* ["level"]=>
|
|
* string(7) "warning"
|
|
* ["type"]=>
|
|
* string(23) "SelfDoesntMatchLocation"
|
|
* ["line"]=>
|
|
* string(2) "11"
|
|
* ["column"]=>
|
|
* string(2) "91"
|
|
* ["text"]=>
|
|
* string(46) "Self reference doesn't match document location"
|
|
* ["msgcount"]=>
|
|
* string(1) "1"
|
|
* ["backupcolumn"]=>
|
|
* string(2) "91"
|
|
* ["backupline"]=>
|
|
* string(2) "11"
|
|
* ["element"]=>
|
|
* string(4) "href"
|
|
* ["parent"]=>
|
|
* string(7) "channel"
|
|
* }
|
|
* 1 => etc ..
|
|
* }
|
|
* }
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getWarnings()
|
|
{
|
|
$warnings = [];
|
|
$xPathQuery = "/env:Envelope/env:Body/m:feedvalidationresponse/m:warnings/m:warninglist/*";
|
|
$warningList = $this->DOMXpath->query($xPathQuery);
|
|
if ($warningList->length > 0) {
|
|
foreach ($warningList as $warning) {
|
|
$warnings[] = $this->domNodeToArray($warning);
|
|
}
|
|
}
|
|
|
|
return $warnings;
|
|
}
|
|
|
|
/**
|
|
* Get an array with all errors as follow
|
|
* @return array
|
|
*/
|
|
public function getErrors()
|
|
{
|
|
$errors = [];
|
|
$xPathQuery = "/env:Envelope/env:Body/m:feedvalidationresponse/m:errors/m:errorlist/*";
|
|
$errorList = $this->DOMXpath->query($xPathQuery);
|
|
if ($errorList->length > 0) {
|
|
foreach ($errorList as $error) {
|
|
$errors[] = $this->domNodeToArray($error);
|
|
}
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
|
|
/**
|
|
* @source http://www.ermshaus.org/2010/12/php-transform-domnode-to-array
|
|
*
|
|
* Transforms the contents of a DOMNode to an associative array
|
|
*
|
|
* XML node names become array keys, attributes will be discarded. If $node
|
|
* doesn't contain child nodes, a string will be returned.
|
|
*
|
|
* @param DOMNode $node DOMDocument node
|
|
* @return string|array Associative array or string with node content
|
|
*/
|
|
private function domNodeToArray(DOMNode $node)
|
|
{
|
|
$ret = '';
|
|
|
|
if ($node->hasChildNodes()) {
|
|
if ($node->firstChild === $node->lastChild && $node->firstChild->nodeType === XML_TEXT_NODE) {
|
|
// Node contains nothing but a text node, return its value
|
|
$ret = trim($node->nodeValue);
|
|
} else {
|
|
// Otherwise, do recursion
|
|
$ret = [];
|
|
foreach ($node->childNodes as $child) {
|
|
if ($child->nodeType !== XML_TEXT_NODE) {
|
|
// If there's more than one node with this node name on the
|
|
// current level, create an array
|
|
if (isset($ret[$child->nodeName])) {
|
|
if ( ! is_array($ret[$child->nodeName]) || ! isset($ret[$child->nodeName][0])) {
|
|
$tmp = $ret[$child->nodeName];
|
|
$ret[$child->nodeName] = [];
|
|
$ret[$child->nodeName][] = $tmp;
|
|
}
|
|
|
|
$ret[$child->nodeName][] = $this->domNodeToArray($child);
|
|
} else {
|
|
$ret[$child->nodeName] = $this->domNodeToArray($child);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
}
|