Completed
Push — kraftbj-patch-2 ( 82c983...ae9d16 )
by
unknown
513:58 queued 503:20
created

Jetpack_Sitemap_Buffer::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 16
nc 1
nop 5
dl 0
loc 20
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Sitemaps (per the protocol) are essentially lists of XML fragments;
4
 * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer
5
 * class abstracts the details of constructing these lists while
6
 * maintaining the constraints.
7
 *
8
 * @since 4.7.0
9
 * @package Jetpack
10
 */
11
12
/**
13
 * A buffer for constructing sitemap xml files.
14
 *
15
 * Models a list of strings such that
16
 *
17
 * 1. the list must have a bounded number of entries,
18
 * 2. the concatenation of the strings must have bounded
19
 *      length (including some header and footer strings), and
20
 * 3. each item has a timestamp, and we need to keep track
21
 *      of the most recent timestamp of the items in the list.
22
 *
23
 * @since 4.7.0
24
 */
25
class Jetpack_Sitemap_Buffer {
26
27
	/**
28
	 * Largest number of items the buffer can hold.
29
	 *
30
	 * @access private
31
	 * @since 4.7.0
32
	 * @var int $item_capacity The item capacity.
33
	 */
34
	private $item_capacity;
35
36
	/**
37
	 * Largest number of bytes the buffer can hold.
38
	 *
39
	 * @access private
40
	 * @since 4.7.0
41
	 * @var int $byte_capacity The byte capacity.
42
	 */
43
	private $byte_capacity;
44
45
	/**
46
	 * Footer text of the buffer; stored here so it can be appended when the buffer is full.
47
	 *
48
	 * @access private
49
	 * @since 4.7.0
50
	 * @var string $footer_text The footer text.
51
	 */
52
	private $footer_text;
53
54
	/**
55
	 * The buffer contents.
56
	 *
57
	 * @access private
58
	 * @since 4.7.0
59
	 * @var string The buffer contents.
60
	 */
61
	private $buffer;
62
63
	/**
64
	 * Flag which detects when the buffer is full.
65
	 *
66
	 * @access private
67
	 * @since 4.7.0
68
	 * @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.
69
	 */
70
	private $is_full_flag;
71
72
	/**
73
	 * Flag which detects when the buffer is empty.
74
	 *
75
	 * @access private
76
	 * @since 4.7.0
77
	 * @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.
78
	 */
79
	private $is_empty_flag;
80
81
	/**
82
	 * The most recent timestamp seen by the buffer.
83
	 *
84
	 * @access private
85
	 * @since 4.7.0
86
	 * @var string $timestamp Must be in 'YYYY-MM-DD hh:mm:ss' format.
87
	 */
88
	private $timestamp;
89
90
	/**
91
	 * Construct a new Jetpack_Sitemap_Buffer.
92
	 *
93
	 * @since 4.7.0
94
	 *
95
	 * @param int    $item_limit The maximum size of the buffer in items.
96
	 * @param int    $byte_limit The maximum size of the buffer in bytes.
97
	 * @param string $header The string to prepend to the entire buffer.
98
	 * @param string $footer The string to append to the entire buffer.
99
	 * @param string $time The initial datetime of the buffer. Must be in 'YYYY-MM-DD hh:mm:ss' format.
100
	 */
101
	public function __construct(
102
		$item_limit,
103
		$byte_limit,
104
		$header = '',
105
		$footer = '',
106
		$time
0 ignored issues
show
Coding Style introduced by
Parameters which have default values should be placed at the end.

If you place a parameter with a default value before a parameter with a default value, the default value of the first parameter will never be used as it will always need to be passed anyway:

// $a must always be passed; it's default value is never used.
function someFunction($a = 5, $b) { }
Loading history...
107
	) {
108
		$this->item_capacity = max( 1, intval( $item_limit ) );
109
110
		mbstring_binary_safe_encoding(); // So we can safely use strlen().
111
		$this->byte_capacity = max( 1, intval( $byte_limit ) ) - strlen( $header ) - strlen( $footer );
112
		reset_mbstring_encoding();
113
114
		$this->footer_text = $footer;
115
		$this->buffer = $header;
116
		$this->is_full_flag = false;
117
		$this->is_empty_flag = true;
118
		$this->timestamp = $time;
119
		return;
120
	}
121
122
	/**
123
	 * Append an item to the buffer, if there is room for it,
124
	 * and set is_empty_flag to false. If there is no room,
125
	 * we set is_full_flag to true. If $item is null,
126
	 * don't do anything and report success.
127
	 *
128
	 * @since 4.7.0
129
	 *
130
	 * @param string $item The item to be added.
131
	 *
132
	 * @return bool True if the append succeeded, False if not.
133
	 */
134
	public function try_to_add_item( $item ) {
135
		if ( is_null( $item ) ) {
136
			return true;
137
		} else {
138
139
			mbstring_binary_safe_encoding(); // So we can safely use strlen().
140
			$item_size = strlen( $item ); // Size in bytes.
141
			reset_mbstring_encoding();
142
143
			if ( 0 >= $this->item_capacity || 0 > $this->byte_capacity - $item_size ) {
144
				$this->is_full_flag = true;
145
				return false;
146
			} else {
147
				$this->is_empty_flag = false;
148
				$this->item_capacity -= 1;
149
				$this->byte_capacity -= $item_size;
150
				$this->buffer .= $item;
151
				return true;
152
			}
153
		}
154
	}
155
156
	/**
157
	 * Retrieve the contents of the buffer.
158
	 *
159
	 * @since 4.7.0
160
	 *
161
	 * @return string The contents of the buffer (with the footer included).
162
	 */
163
	public function contents() {
164
		return $this->buffer . $this->footer_text;
165
	}
166
167
	/**
168
	 * Detect whether the buffer is full.
169
	 *
170
	 * @since 4.7.0
171
	 *
172
	 * @return bool True if the buffer is full, false otherwise.
173
	 */
174
	public function is_full() {
175
		return $this->is_full_flag;
176
	}
177
178
	/**
179
	 * Detect whether the buffer is empty.
180
	 *
181
	 * @since 4.7.0
182
	 *
183
	 * @return bool True if the buffer is empty, false otherwise.
184
	 */
185
	public function is_empty() {
186
		return $this->is_empty_flag;
187
	}
188
189
	/**
190
	 * Update the timestamp of the buffer.
191
	 *
192
	 * @since 4.7.0
193
	 *
194
	 * @param string $new_time A datetime string in 'YYYY-MM-DD hh:mm:ss' format.
195
	 */
196
	public function view_time( $new_time ) {
197
		$this->timestamp = max( $this->timestamp, $new_time );
198
		return;
199
	}
200
201
	/**
202
	 * Retrieve the timestamp of the buffer.
203
	 *
204
	 * @since 4.7.0
205
	 *
206
	 * @return string A datetime string in 'YYYY-MM-DD hh:mm:ss' format.
207
	 */
208
	public function last_modified() {
209
		return $this->timestamp;
210
	}
211
212
	/**
213
	 * Render an associative array as an XML string. This is needed because
214
	 * SimpleXMLElement only handles valid XML, but we sometimes want to
215
	 * pass around (possibly invalid) fragments. Note that 'null' values make
216
	 * a tag self-closing; this is only sometimes correct (depending on the
217
	 * version of HTML/XML); see the list of 'void tags'.
218
	 *
219
	 * Example:
220
	 *
221
	 * array(
222
	 *   'html' => array(                    |<html xmlns="foo">
223
	 *     'head' => array(                  |  <head>
224
	 *       'title' => 'Woo!',              |    <title>Woo!</title>
225
	 *     ),                                |  </head>
226
	 *     'body' => array(             ==>  |  <body>
227
	 *       'h2' => 'Some thing',           |    <h2>Some thing</h2>
228
	 *       'p'  => 'it's all up ons',      |    <p>it's all up ons</p>
229
	 *       'br' => null,                   |    <br />
230
	 *     ),                                |  </body>
231
	 *   ),                                  |</html>
232
	 * )
233
	 *
234
	 * @access public
235
	 * @since 3.9.0
236
	 * @since 4.7.0 Rename, add $depth parameter, and change return type.
237
	 *
238
	 * @param array  $array A recursive associative array of tag/child relationships.
239
	 * @param string $depth String to prepend to each line. For internal use only.
240
	 *
241
	 * @return string The rendered XML string.
242
	 */
243
	public static function array_to_xml_string( $array, $depth = '' ) {
244
		$string = '';
245
246
		foreach ( $array as $key => $value ) {
247
248
			// Only allow a-z, A-Z, colon, underscore, and hyphen.
249
			$tag = preg_replace( '/[^a-zA-Z:_-]/', '_', $key );
250
251
			if ( is_array( $value ) ) {
252
				$string .= $depth . "<$tag>\n";
253
				$string .= self::array_to_xml_string( $value, $depth . '  ' );
254
				$string .= $depth . "</$tag>\n";
255
			} elseif ( is_null( $value ) ) {
256
				$string .= $depth . "<$tag />\n";
257
			} else {
258
				$string .= $depth . "<$tag>" . ent2ncr( $value ) . "</$tag>\n";
259
			}
260
		}
261
262
		return $string;
263
	}
264
265
	/**
266
	 * Render an associative array of XML attribute key/value pairs.
267
	 *
268
	 * @access public
269
	 * @since 4.7.0
270
	 *
271
	 * @param array $array Key/value array of attributes.
272
	 *
273
	 * @return string The rendered attribute string.
274
	 */
275
	public static function array_to_xml_attr_string( $array ) {
276
		$string = '';
277
278
		foreach ( $array as $key => $value ) {
279
			$key = preg_replace( '/[^a-zA-Z:_-]/', '_', $key );
280
			$string .= ' ' . $key . '="' . esc_attr( $value ) . '"';
281
		}
282
283
		return $string;
284
	}
285
286
}
287