| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- <?php
- /**
- * Sitemaps (per the protocol) are essentially lists of XML fragments;
- * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer
- * class abstracts the details of constructing these lists while
- * maintaining the constraints.
- *
- * @since 4.8.0
- * @package Jetpack
- */
- /**
- * A buffer for constructing sitemap xml files.
- *
- * Models a list of strings such that
- *
- * 1. the list must have a bounded number of entries,
- * 2. the concatenation of the strings must have bounded
- * length (including some header and footer strings), and
- * 3. each item has a timestamp, and we need to keep track
- * of the most recent timestamp of the items in the list.
- *
- * @since 4.8.0
- */
- abstract class Jetpack_Sitemap_Buffer {
- /**
- * Largest number of items the buffer can hold.
- *
- * @access protected
- * @since 4.8.0
- * @var int $item_capacity The item capacity.
- */
- protected $item_capacity;
- /**
- * Largest number of bytes the buffer can hold.
- *
- * @access protected
- * @since 4.8.0
- * @var int $byte_capacity The byte capacity.
- */
- protected $byte_capacity;
- /**
- * Flag which detects when the buffer is full.
- *
- * @access protected
- * @since 4.8.0
- * @var bool $is_full_flag The flag value. This flag is set to false on construction and only flipped to true if we've tried to add something and failed.
- */
- protected $is_full_flag;
- /**
- * Flag which detects when the buffer is empty.
- *
- * @access protected
- * @since 4.8.0
- * @var bool $is_empty_flag The flag value. This flag is set to true on construction and only flipped to false if we've tried to add something and succeeded.
- */
- protected $is_empty_flag;
- /**
- * The most recent timestamp seen by the buffer.
- *
- * @access protected
- * @since 4.8.0
- * @var string $timestamp Must be in 'YYYY-MM-DD hh:mm:ss' format.
- */
- protected $timestamp;
- /**
- * The DOM document object that is currently being used to construct the XML doc.
- *
- * @access protected
- * @since 5.3.0
- * @var DOMDocument $doc
- */
- protected $doc = null;
- /**
- * The root DOM element object that holds everything inside. Do not use directly, call
- * the get_root_element getter method instead.
- *
- * @access protected
- * @since 5.3.0
- * @var DOMElement $doc
- */
- protected $root = null;
- /**
- * Helper class to construct sitemap paths.
- *
- * @since 5.3.0
- * @protected
- * @var Jetpack_Sitemap_Finder
- */
- protected $finder;
- /**
- * Construct a new Jetpack_Sitemap_Buffer.
- *
- * @since 4.8.0
- *
- * @param int $item_limit The maximum size of the buffer in items.
- * @param int $byte_limit The maximum size of the buffer in bytes.
- * @param string $time The initial datetime of the buffer. Must be in 'YYYY-MM-DD hh:mm:ss' format.
- */
- public function __construct( $item_limit, $byte_limit, $time ) {
- $this->is_full_flag = false;
- $this->timestamp = $time;
- $this->finder = new Jetpack_Sitemap_Finder();
- $this->doc = new DOMDocument( '1.0', 'UTF-8' );
- $this->item_capacity = max( 1, intval( $item_limit ) );
- $this->byte_capacity = max( 1, intval( $byte_limit ) ) - strlen( $this->doc->saveXML() );
- }
- /**
- * Returns a DOM element that contains all sitemap elements.
- *
- * @access protected
- * @since 5.3.0
- * @return DOMElement $root
- */
- abstract protected function get_root_element();
- /**
- * Append an item to the buffer, if there is room for it,
- * and set is_empty_flag to false. If there is no room,
- * we set is_full_flag to true. If $item is null,
- * don't do anything and report success.
- *
- * @since 4.8.0
- *
- * @param string $item The item to be added.
- *
- * @return bool True if the append succeeded, False if not.
- */
- public function try_to_add_item( $item ) {
- _deprecated_function(
- 'Jetpack_Sitemap_Buffer::try_to_add_item',
- '5.3.0',
- 'Jetpack_Sitemap_Buffer::append'
- );
- $this->append( $item );
- }
- /**
- * Append an item to the buffer, if there is room for it,
- * and set is_empty_flag to false. If there is no room,
- * we set is_full_flag to true. If $item is null,
- * don't do anything and report success.
- *
- * @since 5.3.0
- *
- * @param array $array The item to be added.
- *
- * @return bool True if the append succeeded, False if not.
- */
- public function append( $array ) {
- if ( is_null( $array ) ) {
- return true;
- }
- if ( $this->is_full_flag ) {
- return false;
- }
- if ( 0 >= $this->item_capacity || 0 >= $this->byte_capacity ) {
- $this->is_full_flag = true;
- return false;
- } else {
- $this->item_capacity -= 1;
- $added_element = $this->array_to_xml_string( $array, $this->get_root_element(), $this->doc );
- $this->byte_capacity -= strlen( $this->doc->saveXML( $added_element ) );
- return true;
- }
- }
- /**
- * Retrieve the contents of the buffer.
- *
- * @since 4.8.0
- *
- * @return string The contents of the buffer (with the footer included).
- */
- public function contents() {
- if( $this->is_empty() ) {
- // The sitemap should have at least the root element added to the DOM
- $this->get_root_element();
- }
- return $this->doc->saveXML();
- }
- /**
- * Retrieve the document object.
- *
- * @since 5.3.0
- * @return DOMDocument $doc
- */
- public function get_document() {
- return $this->doc;
- }
- /**
- * Detect whether the buffer is full.
- *
- * @since 4.8.0
- *
- * @return bool True if the buffer is full, false otherwise.
- */
- public function is_full() {
- return $this->is_full_flag;
- }
- /**
- * Detect whether the buffer is empty.
- *
- * @since 4.8.0
- *
- * @return bool True if the buffer is empty, false otherwise.
- */
- public function is_empty() {
- return (
- ! isset( $this->root )
- || ! $this->root->hasChildNodes()
- );
- }
- /**
- * Update the timestamp of the buffer.
- *
- * @since 4.8.0
- *
- * @param string $new_time A datetime string in 'YYYY-MM-DD hh:mm:ss' format.
- */
- public function view_time( $new_time ) {
- $this->timestamp = max( $this->timestamp, $new_time );
- }
- /**
- * Retrieve the timestamp of the buffer.
- *
- * @since 4.8.0
- *
- * @return string A datetime string in 'YYYY-MM-DD hh:mm:ss' format.
- */
- public function last_modified() {
- return $this->timestamp;
- }
- /**
- * Render an associative array as an XML string. This is needed because
- * SimpleXMLElement only handles valid XML, but we sometimes want to
- * pass around (possibly invalid) fragments. Note that 'null' values make
- * a tag self-closing; this is only sometimes correct (depending on the
- * version of HTML/XML); see the list of 'void tags'.
- *
- * Example:
- *
- * array(
- * 'html' => array( |<html xmlns="foo">
- * 'head' => array( | <head>
- * 'title' => 'Woo!', | <title>Woo!</title>
- * ), | </head>
- * 'body' => array( ==> | <body>
- * 'h2' => 'Some thing', | <h2>Some thing</h2>
- * 'p' => 'it's all up ons', | <p>it's all up ons</p>
- * 'br' => null, | <br />
- * ), | </body>
- * ), |</html>
- * )
- *
- * @access protected
- * @since 3.9.0
- * @since 4.8.0 Rename, add $depth parameter, and change return type.
- * @since 5.3.0 Refactor, remove $depth parameter, add $parent and $root, make access protected.
- *
- * @param array $array A recursive associative array of tag/child relationships.
- * @param DOMElement $parent (optional) an element to which new children should be added.
- * @param DOMDocument $root (optional) the parent document.
- *
- * @return string|DOMDocument The rendered XML string or an object if root element is specified.
- */
- protected function array_to_xml_string( $array, $parent = null, $root = null ) {
- $return_string = false;
- if ( null === $parent ) {
- $return_string = true;
- $parent = $root = new DOMDocument();
- }
- if ( is_array( $array ) ) {
- foreach ( $array as $key => $value ) {
- $element = $root->createElement( $key );
- $parent->appendChild( $element );
- if ( is_array( $value ) ) {
- foreach ( $value as $child_key => $child_value ) {
- $child = $root->createElement( $child_key );
- $element->appendChild( $child );
- $child->appendChild( self::array_to_xml_string( $child_value, $child, $root ) );
- }
- } else {
- $element->appendChild(
- $root->createTextNode( $value )
- );
- }
- }
- } else {
- $element = $root->createTextNode( $array );
- $parent->appendChild( $element );
- }
- if ( $return_string ) {
- return $root->saveHTML();
- } else {
- return $element;
- }
- }
- }
|