summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/modules/sitemaps/sitemap-buffer.php')
-rw-r--r--plugins/jetpack/modules/sitemaps/sitemap-buffer.php286
1 files changed, 286 insertions, 0 deletions
diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer.php
new file mode 100644
index 00000000..f1a8d9b1
--- /dev/null
+++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer.php
@@ -0,0 +1,286 @@
+<?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
+ */
+class Jetpack_Sitemap_Buffer {
+
+ /**
+ * Largest number of items the buffer can hold.
+ *
+ * @access private
+ * @since 4.8.0
+ * @var int $item_capacity The item capacity.
+ */
+ private $item_capacity;
+
+ /**
+ * Largest number of bytes the buffer can hold.
+ *
+ * @access private
+ * @since 4.8.0
+ * @var int $byte_capacity The byte capacity.
+ */
+ private $byte_capacity;
+
+ /**
+ * Footer text of the buffer; stored here so it can be appended when the buffer is full.
+ *
+ * @access private
+ * @since 4.8.0
+ * @var string $footer_text The footer text.
+ */
+ private $footer_text;
+
+ /**
+ * The buffer contents.
+ *
+ * @access private
+ * @since 4.8.0
+ * @var string The buffer contents.
+ */
+ private $buffer;
+
+ /**
+ * Flag which detects when the buffer is full.
+ *
+ * @access private
+ * @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.
+ */
+ private $is_full_flag;
+
+ /**
+ * Flag which detects when the buffer is empty.
+ *
+ * @access private
+ * @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.
+ */
+ private $is_empty_flag;
+
+ /**
+ * The most recent timestamp seen by the buffer.
+ *
+ * @access private
+ * @since 4.8.0
+ * @var string $timestamp Must be in 'YYYY-MM-DD hh:mm:ss' format.
+ */
+ private $timestamp;
+
+ /**
+ * 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 $header The string to prepend to the entire buffer.
+ * @param string $footer The string to append to the entire buffer.
+ * @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,
+ $header = '',
+ $footer = '',
+ $time
+ ) {
+ $this->item_capacity = max( 1, intval( $item_limit ) );
+
+ mbstring_binary_safe_encoding(); // So we can safely use strlen().
+ $this->byte_capacity = max( 1, intval( $byte_limit ) ) - strlen( $header ) - strlen( $footer );
+ reset_mbstring_encoding();
+
+ $this->footer_text = $footer;
+ $this->buffer = $header;
+ $this->is_full_flag = false;
+ $this->is_empty_flag = true;
+ $this->timestamp = $time;
+ return;
+ }
+
+ /**
+ * 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 ) {
+ if ( is_null( $item ) ) {
+ return true;
+ } else {
+
+ mbstring_binary_safe_encoding(); // So we can safely use strlen().
+ $item_size = strlen( $item ); // Size in bytes.
+ reset_mbstring_encoding();
+
+ if ( 0 >= $this->item_capacity || 0 > $this->byte_capacity - $item_size ) {
+ $this->is_full_flag = true;
+ return false;
+ } else {
+ $this->is_empty_flag = false;
+ $this->item_capacity -= 1;
+ $this->byte_capacity -= $item_size;
+ $this->buffer .= $item;
+ 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() {
+ return $this->buffer . $this->footer_text;
+ }
+
+ /**
+ * 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 $this->is_empty_flag;
+ }
+
+ /**
+ * 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 );
+ return;
+ }
+
+ /**
+ * 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 public
+ * @since 3.9.0
+ * @since 4.8.0 Rename, add $depth parameter, and change return type.
+ *
+ * @param array $array A recursive associative array of tag/child relationships.
+ * @param string $depth String to prepend to each line. For internal use only.
+ *
+ * @return string The rendered XML string.
+ */
+ public static function array_to_xml_string( $array, $depth = '' ) {
+ $string = '';
+
+ foreach ( $array as $key => $value ) {
+
+ // Only allow a-z, A-Z, colon, underscore, and hyphen.
+ $tag = preg_replace( '/[^a-zA-Z:_-]/', '_', $key );
+
+ if ( is_array( $value ) ) {
+ $string .= $depth . "<$tag>\n";
+ $string .= self::array_to_xml_string( $value, $depth . ' ' );
+ $string .= $depth . "</$tag>\n";
+ } elseif ( is_null( $value ) ) {
+ $string .= $depth . "<$tag />\n";
+ } else {
+ $string .= $depth . "<$tag>" . ent2ncr( $value ) . "</$tag>\n";
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Render an associative array of XML attribute key/value pairs.
+ *
+ * @access public
+ * @since 4.8.0
+ *
+ * @param array $array Key/value array of attributes.
+ *
+ * @return string The rendered attribute string.
+ */
+ public static function array_to_xml_attr_string( $array ) {
+ $string = '';
+
+ foreach ( $array as $key => $value ) {
+ $key = preg_replace( '/[^a-zA-Z:_-]/', '_', $key );
+ $string .= ' ' . $key . '="' . esc_attr( $value ) . '"';
+ }
+
+ return $string;
+ }
+
+}