parser = new HTMLPurifier_VarParser (); } /** * Validates a fully-formed interchange object. * * @param HTMLPurifier_ConfigSchema_Interchange $interchange * @return bool */ public function validate($interchange) { $this->interchange = $interchange; $this->aliases = array (); // PHP is a bit lax with integer <=> string conversions in // arrays, so we don't use the identical !== comparison foreach ( $interchange->directives as $i => $directive ) { $id = $directive->id->toString (); if ($i != $id) { $this->error ( false, "Integrity violation: key '$i' does not match internal id '$id'" ); } $this->validateDirective ( $directive ); } return true; } /** * Validates a HTMLPurifier_ConfigSchema_Interchange_Id object. * * @param HTMLPurifier_ConfigSchema_Interchange_Id $id */ public function validateId($id) { $id_string = $id->toString (); $this->context [] = "id '$id_string'"; if (! $id instanceof HTMLPurifier_ConfigSchema_Interchange_Id) { // handled by InterchangeBuilder $this->error ( false, 'is not an instance of HTMLPurifier_ConfigSchema_Interchange_Id' ); } // keys are now unconstrained (we might want to narrow down to A-Za-z0-9.) // we probably should check that it has at least one namespace $this->with ( $id, 'key' )->assertNotEmpty ()->assertIsString (); // implicit assertIsString handled by InterchangeBuilder array_pop ( $this->context ); } /** * Validates a HTMLPurifier_ConfigSchema_Interchange_Directive object. * * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d */ public function validateDirective($d) { $id = $d->id->toString (); $this->context [] = "directive '$id'"; $this->validateId ( $d->id ); $this->with ( $d, 'description' )->assertNotEmpty (); // BEGIN - handled by InterchangeBuilder $this->with ( $d, 'type' )->assertNotEmpty (); $this->with ( $d, 'typeAllowsNull' )->assertIsBool (); try { // This also tests validity of $d->type $this->parser->parse ( $d->default, $d->type, $d->typeAllowsNull ); } catch ( HTMLPurifier_VarParserException $e ) { $this->error ( 'default', 'had error: ' . $e->getMessage () ); } // END - handled by InterchangeBuilder if (! is_null ( $d->allowed ) || ! empty ( $d->valueAliases )) { // allowed and valueAliases require that we be dealing with // strings, so check for that early. $d_int = HTMLPurifier_VarParser::$types [$d->type]; if (! isset ( HTMLPurifier_VarParser::$stringTypes [$d_int] )) { $this->error ( 'type', 'must be a string type when used with allowed or value aliases' ); } } $this->validateDirectiveAllowed ( $d ); $this->validateDirectiveValueAliases ( $d ); $this->validateDirectiveAliases ( $d ); array_pop ( $this->context ); } /** * Extra validation if $allowed member variable of * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. * * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d */ public function validateDirectiveAllowed($d) { if (is_null ( $d->allowed )) { return; } $this->with ( $d, 'allowed' )->assertNotEmpty ()->assertIsLookup (); // handled by InterchangeBuilder if (is_string ( $d->default ) && ! isset ( $d->allowed [$d->default] )) { $this->error ( 'default', 'must be an allowed value' ); } $this->context [] = 'allowed'; foreach ( $d->allowed as $val => $x ) { if (! is_string ( $val )) { $this->error ( "value $val", 'must be a string' ); } } array_pop ( $this->context ); } /** * Extra validation if $valueAliases member variable of * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. * * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d */ public function validateDirectiveValueAliases($d) { if (is_null ( $d->valueAliases )) { return; } $this->with ( $d, 'valueAliases' )->assertIsArray (); // handled by InterchangeBuilder $this->context [] = 'valueAliases'; foreach ( $d->valueAliases as $alias => $real ) { if (! is_string ( $alias )) { $this->error ( "alias $alias", 'must be a string' ); } if (! is_string ( $real )) { $this->error ( "alias target $real from alias '$alias'", 'must be a string' ); } if ($alias === $real) { $this->error ( "alias '$alias'", "must not be an alias to itself" ); } } if (! is_null ( $d->allowed )) { foreach ( $d->valueAliases as $alias => $real ) { if (isset ( $d->allowed [$alias] )) { $this->error ( "alias '$alias'", 'must not be an allowed value' ); } elseif (! isset ( $d->allowed [$real] )) { $this->error ( "alias '$alias'", 'must be an alias to an allowed value' ); } } } array_pop ( $this->context ); } /** * Extra validation if $aliases member variable of * HTMLPurifier_ConfigSchema_Interchange_Directive is defined. * * @param HTMLPurifier_ConfigSchema_Interchange_Directive $d */ public function validateDirectiveAliases($d) { $this->with ( $d, 'aliases' )->assertIsArray (); // handled by InterchangeBuilder $this->context [] = 'aliases'; foreach ( $d->aliases as $alias ) { $this->validateId ( $alias ); $s = $alias->toString (); if (isset ( $this->interchange->directives [$s] )) { $this->error ( "alias '$s'", 'collides with another directive' ); } if (isset ( $this->aliases [$s] )) { $other_directive = $this->aliases [$s]; $this->error ( "alias '$s'", "collides with alias for directive '$other_directive'" ); } $this->aliases [$s] = $d->id->toString (); } array_pop ( $this->context ); } // protected helper functions /** * Convenience function for generating HTMLPurifier_ConfigSchema_ValidatorAtom * for validating simple member variables of objects. * * @param * $obj * @param * $member * @return HTMLPurifier_ConfigSchema_ValidatorAtom */ protected function with($obj, $member) { return new HTMLPurifier_ConfigSchema_ValidatorAtom ( $this->getFormattedContext (), $obj, $member ); } /** * Emits an error, providing helpful context. * * @throws HTMLPurifier_ConfigSchema_Exception */ protected function error($target, $msg) { if ($target !== false) { $prefix = ucfirst ( $target ) . ' in ' . $this->getFormattedContext (); } else { $prefix = ucfirst ( $this->getFormattedContext () ); } throw new HTMLPurifier_ConfigSchema_Exception ( trim ( $prefix . ' ' . $msg ) ); } /** * Returns a formatted context string. * * @return string */ protected function getFormattedContext() { return implode ( ' in ', array_reverse ( $this->context ) ); } } // vim: et sw=4 sts=4