|
1
|
|
|
<?php |
|
|
|
|
|
|
2
|
|
|
/** |
|
3
|
|
|
* PhpQuery is a server-side, chainable, CSS3 selector driven |
|
4
|
|
|
* Document Object Model (DOM) API based on jQuery JavaScript Library. |
|
5
|
|
|
* |
|
6
|
|
|
* @version 0.9.5 |
|
7
|
|
|
* @link http://code.google.com/p/phpquery/ |
|
8
|
|
|
* @link http://phpquery-library.blogspot.com/ |
|
9
|
|
|
* @link http://jquery.com/ |
|
10
|
|
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> |
|
11
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php MIT License |
|
12
|
|
|
* @package PhpQuery |
|
13
|
|
|
*/ |
|
14
|
|
|
|
|
15
|
|
|
namespace PhpQuery; |
|
16
|
|
|
|
|
17
|
|
|
require_once __DIR__ . '/bootstrap.php'; |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Shortcut to PhpQuery::pq($arg1, $context) |
|
21
|
|
|
* Chainable. |
|
22
|
|
|
* |
|
23
|
|
|
* @see PhpQuery::pq() |
|
24
|
|
|
* @param $arg1 |
|
25
|
|
|
* @param null $context |
|
26
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
27
|
|
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> |
|
28
|
|
|
* @package PhpQuery |
|
29
|
|
|
*/ |
|
30
|
|
|
function pq($arg1, $context = null) |
|
31
|
|
|
{ |
|
32
|
|
|
return PhpQuery::pq($arg1, $context); |
|
33
|
|
|
} |
|
34
|
|
|
|
|
35
|
|
|
/** |
|
36
|
|
|
* Static namespace for PhpQuery functions. |
|
37
|
|
|
* |
|
38
|
|
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> |
|
39
|
|
|
* @package PhpQuery |
|
40
|
|
|
*/ |
|
41
|
|
|
abstract class PhpQuery |
|
42
|
|
|
{ |
|
43
|
|
|
/** |
|
44
|
|
|
* XXX: Workaround for mbstring problems |
|
45
|
|
|
* |
|
46
|
|
|
* @var bool |
|
47
|
|
|
*/ |
|
48
|
|
|
public static $mbstringSupport = true; |
|
49
|
|
|
public static $debug = false; |
|
50
|
|
|
public static $documents = array(); |
|
51
|
|
|
public static $defaultDocumentID = null; |
|
52
|
|
|
// public static $defaultDoctype = 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"'; |
|
|
|
|
|
|
53
|
|
|
/** |
|
54
|
|
|
* Applies only to HTML. |
|
55
|
|
|
* |
|
56
|
|
|
* @var string |
|
57
|
|
|
*/ |
|
58
|
|
|
public static $defaultDoctype = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
|
59
|
|
|
"http://www.w3.org/TR/html4/loose.dtd">'; |
|
60
|
|
|
public static $defaultCharset = 'UTF-8'; |
|
61
|
|
|
/** |
|
62
|
|
|
* Static namespace for plugins. |
|
63
|
|
|
* |
|
64
|
|
|
* @var object |
|
65
|
|
|
*/ |
|
66
|
|
|
public static $plugins = array(); |
|
67
|
|
|
/** |
|
68
|
|
|
* List of loaded plugins. |
|
69
|
|
|
* |
|
70
|
|
|
* @var array |
|
71
|
|
|
*/ |
|
72
|
|
|
public static $pluginsLoaded = array(); |
|
73
|
|
|
public static $pluginsMethods = array(); |
|
74
|
|
|
public static $pluginsStaticMethods = array(); |
|
75
|
|
|
public static $extendMethods = array(); |
|
76
|
|
|
/** |
|
77
|
|
|
* @TODO implement |
|
78
|
|
|
*/ |
|
79
|
|
|
public static $extendStaticMethods = array(); |
|
80
|
|
|
/** |
|
81
|
|
|
* Hosts allowed for AJAX connections. |
|
82
|
|
|
* Dot '.' means $_SERVER['HTTP_HOST'] (if any). |
|
83
|
|
|
* |
|
84
|
|
|
* @var array |
|
85
|
|
|
*/ |
|
86
|
|
|
public static $ajaxAllowedHosts = array( |
|
87
|
|
|
'.' |
|
88
|
|
|
); |
|
89
|
|
|
/** |
|
90
|
|
|
* AJAX settings. |
|
91
|
|
|
* |
|
92
|
|
|
* @var array |
|
93
|
|
|
* XXX should it be static or not ? |
|
94
|
|
|
*/ |
|
95
|
|
|
public static $ajaxSettings = array( |
|
96
|
|
|
'url' => '', |
|
97
|
|
|
//TODO |
|
98
|
|
|
'global' => true, |
|
99
|
|
|
'type' => "GET", |
|
100
|
|
|
'timeout' => null, |
|
101
|
|
|
'contentType' => "application/x-www-form-urlencoded", |
|
102
|
|
|
'processData' => true, |
|
103
|
|
|
// 'async' => true, |
|
|
|
|
|
|
104
|
|
|
'data' => null, |
|
105
|
|
|
'username' => null, |
|
106
|
|
|
'password' => null, |
|
107
|
|
|
'dataType' => null, |
|
108
|
|
|
'ifModified' => null, |
|
109
|
|
|
'accepts' => array( |
|
110
|
|
|
'xml' => "application/xml, text/xml", |
|
111
|
|
|
'html' => "text/html", |
|
112
|
|
|
'script' => "text/javascript, application/javascript", |
|
113
|
|
|
'json' => "application/json, text/javascript", |
|
114
|
|
|
'text' => "text/plain", |
|
115
|
|
|
'_default' => "*/*" |
|
116
|
|
|
) |
|
117
|
|
|
); |
|
118
|
|
|
public static $lastModified = null; |
|
119
|
|
|
public static $active = 0; |
|
120
|
|
|
public static $dumpCount = 0; |
|
121
|
|
|
public static $enableCssShorthand = false; |
|
122
|
|
|
|
|
123
|
|
|
public static function use_function($ns = '\\', $func = 'pq') |
|
124
|
|
|
{ |
|
125
|
|
|
if ($ns{0} !== '\\') { |
|
126
|
|
|
$ns = '\\' . $ns; |
|
127
|
|
|
} |
|
128
|
|
|
if (!function_exists($ns . '\\' . $func)) { |
|
129
|
|
|
if ($ns === '\\') { |
|
130
|
|
|
eval("function $func(\$a, \$b = '') { return \\PhpQuery\\PhpQuery::pq(\$a, \$b); }"); |
|
|
|
|
|
|
131
|
|
|
} else { |
|
132
|
|
|
$ns = substr($ns, 1); |
|
133
|
|
|
eval("namespace $ns { function $func(\$a, \$b = '') { return \\PhpQuery\\PhpQuery::pq(\$a, \$b); } }"); |
|
|
|
|
|
|
134
|
|
|
} |
|
135
|
|
|
} |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
|
|
139
|
|
|
/** |
|
140
|
|
|
* Multi-purpose function. |
|
141
|
|
|
* Use pq() as shortcut. |
|
142
|
|
|
* |
|
143
|
|
|
* In below examples, $pq is any result of pq(); function. |
|
144
|
|
|
* |
|
145
|
|
|
* 1. Import markup into existing document (without any attaching): |
|
146
|
|
|
* - Import into selected document: |
|
147
|
|
|
* pq('<div/>') // DOESNT accept text nodes at beginning of input string ! |
|
148
|
|
|
* - Import into document with ID from $pq->getDocumentID(): |
|
149
|
|
|
* pq('<div/>', $pq->getDocumentID()) |
|
150
|
|
|
* - Import into same document as \DOMNode belongs to: |
|
151
|
|
|
* pq('<div/>', \DOMNode) |
|
152
|
|
|
* - Import into document from PhpQuery object: |
|
153
|
|
|
* pq('<div/>', $pq) |
|
154
|
|
|
* |
|
155
|
|
|
* 2. Run query: |
|
156
|
|
|
* - Run query on last selected document: |
|
157
|
|
|
* pq('div.myClass') |
|
158
|
|
|
* - Run query on document with ID from $pq->getDocumentID(): |
|
159
|
|
|
* pq('div.myClass', $pq->getDocumentID()) |
|
160
|
|
|
* - Run query on same document as \DOMNode belongs to and use node(s)as root for query: |
|
161
|
|
|
* pq('div.myClass', \DOMNode) |
|
162
|
|
|
* - Run query on document from PhpQuery object |
|
163
|
|
|
* and use object's stack as root node(s) for query: |
|
164
|
|
|
* pq('div.myClass', $pq) |
|
165
|
|
|
* |
|
166
|
|
|
* @param string|\DOMNode|\DOMNodeList|array $arg1 HTML markup, CSS Selector, \DOMNode or array of \DOMNodes |
|
167
|
|
|
* @param string|PhpQueryObject|\DOMNode $context DOM ID from $pq->getDocumentID(), PhpQuery object (determines also query root) or \DOMNode (determines also query root) |
|
168
|
|
|
* |
|
169
|
|
|
* @throws \Exception |
|
170
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery|QueryTemplatesPhpQuery|false |
|
171
|
|
|
* PhpQuery object or false in case of error. |
|
172
|
|
|
*/ |
|
173
|
|
|
public static function pq($arg1, $context = null) |
|
174
|
|
|
{ |
|
175
|
|
|
if ($arg1 instanceof \DOMNode && !isset($context)) { |
|
176
|
|
|
foreach (PhpQuery::$documents as $documentWrapper) { |
|
177
|
|
|
$compare = $arg1 instanceof \DOMDocument ? $arg1 : $arg1->ownerDocument; |
|
178
|
|
|
if ($documentWrapper->document->isSameNode($compare)) { |
|
179
|
|
|
$context = $documentWrapper->id; |
|
180
|
|
|
} |
|
181
|
|
|
} |
|
182
|
|
|
} |
|
183
|
|
|
if (!$context) { |
|
184
|
|
|
$domId = self::$defaultDocumentID; |
|
185
|
|
|
if (!$domId) { |
|
186
|
|
|
throw new \Exception("Can't use last created DOM, because there isn't any. Use PhpQuery::newDocument() first."); |
|
187
|
|
|
} |
|
188
|
|
|
// } else if (is_object($context) && ($context instanceof PHPQUERY || is_subclass_of($context, 'PhpQueryObject'))) |
|
|
|
|
|
|
189
|
|
|
} else { |
|
190
|
|
|
if (is_object($context) && $context instanceof PhpQueryObject) { |
|
191
|
|
|
$domId = $context->getDocumentID(); |
|
192
|
|
|
} else { |
|
193
|
|
|
if ($context instanceof \DOMDocument) { |
|
194
|
|
|
$domId = self::getDocumentID($context); |
|
195
|
|
|
if (!$domId) { |
|
196
|
|
|
//throw new \Exception('Orphaned \DOMDocument'); |
|
|
|
|
|
|
197
|
|
|
$domId = self::newDocument($context)->getDocumentID(); |
|
198
|
|
|
} |
|
199
|
|
|
} else { |
|
200
|
|
|
if ($context instanceof \DOMNode) { |
|
201
|
|
|
$domId = self::getDocumentID($context); |
|
202
|
|
|
if (!$domId) { |
|
203
|
|
|
throw new \Exception('Orphaned DOMNode'); |
|
204
|
|
|
// $domId = self::newDocument($context->ownerDocument); |
|
|
|
|
|
|
205
|
|
|
} |
|
206
|
|
|
} else { |
|
207
|
|
|
$domId = $context; |
|
208
|
|
|
} |
|
209
|
|
|
} |
|
210
|
|
|
} |
|
211
|
|
|
} |
|
212
|
|
|
if ($arg1 instanceof PhpQueryObject) { |
|
213
|
|
|
// if (is_object($arg1) && (get_class($arg1) == 'PhpQueryObject' || $arg1 instanceof PHPQUERY || is_subclass_of($arg1, 'PhpQueryObject'))) { |
|
|
|
|
|
|
214
|
|
|
/** |
|
215
|
|
|
* Return $arg1 or import $arg1 stack if document differs: |
|
216
|
|
|
* pq(pq('<div/>')) |
|
217
|
|
|
*/ |
|
218
|
|
|
if ($arg1->getDocumentID() == $domId) { |
|
219
|
|
|
return $arg1; |
|
220
|
|
|
} |
|
221
|
|
|
$class = get_class($arg1); |
|
222
|
|
|
// support inheritance by passing old object to overloaded constructor |
|
223
|
|
|
$PhpQuery = $class != 'PhpQuery' ? new $class($arg1, $domId) |
|
|
|
|
|
|
224
|
|
|
: new PhpQueryObject($domId); |
|
225
|
|
|
$PhpQuery->elements = array(); |
|
226
|
|
|
foreach ($arg1->elements as $node) { |
|
227
|
|
|
$PhpQuery->elements[] = $PhpQuery->document->importNode($node, true); |
|
228
|
|
|
} |
|
229
|
|
|
return $PhpQuery; |
|
230
|
|
|
} else { |
|
231
|
|
|
if ($arg1 instanceof \DOMNode |
|
232
|
|
|
|| (is_array($arg1) && isset($arg1[0]) && $arg1[0] instanceof \DOMNode) |
|
233
|
|
|
) { |
|
234
|
|
|
/* |
|
235
|
|
|
* Wrap DOM nodes with PhpQuery object, import into document when needed: |
|
236
|
|
|
* pq(array($domNode1, $domNode2)) |
|
237
|
|
|
*/ |
|
238
|
|
|
$PhpQuery = new PhpQueryObject($domId); |
|
239
|
|
|
if (!($arg1 instanceof \DOMNodeList) && !is_array($arg1)) { |
|
240
|
|
|
$arg1 = array( |
|
241
|
|
|
$arg1 |
|
242
|
|
|
); |
|
243
|
|
|
} |
|
244
|
|
|
$PhpQuery->elements = array(); |
|
245
|
|
|
foreach ($arg1 as $node) { |
|
246
|
|
|
$sameDocument = $node->ownerDocument instanceof \DOMDocument |
|
247
|
|
|
&& !$node->ownerDocument->isSameNode($PhpQuery->document); |
|
248
|
|
|
$PhpQuery->elements[] = $sameDocument ? $PhpQuery->document->importNode($node, true) |
|
249
|
|
|
: $node; |
|
250
|
|
|
} |
|
251
|
|
|
return $PhpQuery; |
|
252
|
|
|
} else { |
|
253
|
|
|
if (self::isMarkup($arg1)) { |
|
|
|
|
|
|
254
|
|
|
/** |
|
255
|
|
|
* Import HTML: |
|
256
|
|
|
* pq('<div/>') |
|
257
|
|
|
*/ |
|
258
|
|
|
$PhpQuery = new PhpQueryObject($domId); |
|
259
|
|
|
return $PhpQuery->newInstance($PhpQuery->documentWrapper->import($arg1)); |
|
260
|
|
|
} else { |
|
261
|
|
|
/** |
|
262
|
|
|
* Run CSS query: |
|
263
|
|
|
* pq('div.myClass') |
|
264
|
|
|
*/ |
|
265
|
|
|
$PhpQuery = new PhpQueryObject($domId); |
|
266
|
|
|
// if ($context && ($context instanceof PHPQUERY || is_subclass_of($context, 'PhpQueryObject'))) |
|
|
|
|
|
|
267
|
|
|
if ($context && $context instanceof PhpQueryObject) { |
|
268
|
|
|
$PhpQuery->elements = $context->elements; |
|
269
|
|
|
} else { |
|
270
|
|
|
if ($context && $context instanceof \DOMNodeList) { |
|
271
|
|
|
$PhpQuery->elements = array(); |
|
272
|
|
|
foreach ($context as $node) { |
|
273
|
|
|
$PhpQuery->elements[] = $node; |
|
274
|
|
|
} |
|
275
|
|
|
} else { |
|
276
|
|
|
if ($context && $context instanceof \DOMNode) { |
|
277
|
|
|
$PhpQuery->elements = array( |
|
278
|
|
|
$context |
|
279
|
|
|
); |
|
280
|
|
|
} |
|
281
|
|
|
} |
|
282
|
|
|
} |
|
283
|
|
|
return $PhpQuery->find($arg1); |
|
284
|
|
|
} |
|
285
|
|
|
} |
|
286
|
|
|
} |
|
287
|
|
|
} |
|
288
|
|
|
|
|
289
|
|
|
/** |
|
290
|
|
|
* Sets default document to $id. Document has to be loaded prior |
|
291
|
|
|
* to using this method. |
|
292
|
|
|
* $id can be retrived via getDocumentID() or getDocumentIDRef(). |
|
293
|
|
|
* |
|
294
|
|
|
* @param string $id |
|
295
|
|
|
*/ |
|
296
|
|
|
public static function selectDocument($id) |
|
297
|
|
|
{ |
|
298
|
|
|
$id = self::getDocumentID($id); |
|
299
|
|
|
self::debug("Selecting document '$id' as default one"); |
|
300
|
|
|
self::$defaultDocumentID = self::getDocumentID($id); |
|
301
|
|
|
} |
|
302
|
|
|
|
|
303
|
|
|
/** |
|
304
|
|
|
* Returns document with id $id or last used as PhpQueryObject. |
|
305
|
|
|
* $id can be retrived via getDocumentID() or getDocumentIDRef(). |
|
306
|
|
|
* Chainable. |
|
307
|
|
|
* |
|
308
|
|
|
* @see PhpQuery::selectDocument() |
|
309
|
|
|
* @param null $id |
|
310
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
311
|
|
|
*/ |
|
312
|
|
|
public static function getDocument($id = null) |
|
313
|
|
|
{ |
|
314
|
|
|
if ($id) |
|
315
|
|
|
PhpQuery::selectDocument($id); |
|
316
|
|
|
else |
|
317
|
|
|
$id = PhpQuery::$defaultDocumentID; |
|
318
|
|
|
return new PhpQueryObject($id); |
|
319
|
|
|
} |
|
320
|
|
|
|
|
321
|
|
|
/** |
|
322
|
|
|
* Creates new document from markup. |
|
323
|
|
|
* Chainable. |
|
324
|
|
|
* |
|
325
|
|
|
* @param null $markup |
|
326
|
|
|
* @param null $contentType |
|
327
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
328
|
|
|
*/ |
|
329
|
|
|
public static function newDocument($markup = null, $contentType = null) |
|
330
|
|
|
{ |
|
331
|
|
|
if (!$markup) |
|
332
|
|
|
$markup = ''; |
|
333
|
|
|
$documentID = PhpQuery::createDocumentWrapper($markup, $contentType); |
|
334
|
|
|
return new PhpQueryObject($documentID); |
|
335
|
|
|
} |
|
336
|
|
|
|
|
337
|
|
|
/** |
|
338
|
|
|
* Creates new document from markup. |
|
339
|
|
|
* Chainable. |
|
340
|
|
|
* |
|
341
|
|
|
* @param null $markup |
|
342
|
|
|
* @param null $charset |
|
343
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
344
|
|
|
*/ |
|
345
|
|
|
public static function newDocumentHTML($markup = null, $charset = null) |
|
346
|
|
|
{ |
|
347
|
|
|
$contentType = $charset ? ";charset=$charset" : ''; |
|
348
|
|
|
return self::newDocument($markup, "text/html{$contentType}"); |
|
349
|
|
|
} |
|
350
|
|
|
|
|
351
|
|
|
/** |
|
352
|
|
|
* Creates new document from markup. |
|
353
|
|
|
* Chainable. |
|
354
|
|
|
* |
|
355
|
|
|
* @param null $markup |
|
356
|
|
|
* @param null $charset |
|
357
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
358
|
|
|
*/ |
|
359
|
|
|
public static function newDocumentXML($markup = null, $charset = null) |
|
360
|
|
|
{ |
|
361
|
|
|
$contentType = $charset ? ";charset=$charset" : ''; |
|
362
|
|
|
return self::newDocument($markup, "text/xml{$contentType}"); |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
/** |
|
366
|
|
|
* Creates new document from markup. |
|
367
|
|
|
* Chainable. |
|
368
|
|
|
* |
|
369
|
|
|
* @param null $markup |
|
370
|
|
|
* @param null $charset |
|
371
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
372
|
|
|
*/ |
|
373
|
|
|
public static function newDocumentXHTML($markup = null, $charset = null) |
|
374
|
|
|
{ |
|
375
|
|
|
$contentType = $charset ? ";charset=$charset" : ''; |
|
376
|
|
|
return self::newDocument($markup, "application/xhtml+xml{$contentType}"); |
|
377
|
|
|
} |
|
378
|
|
|
|
|
379
|
|
|
/** |
|
380
|
|
|
* Creates new document from markup. |
|
381
|
|
|
* Chainable. |
|
382
|
|
|
* |
|
383
|
|
|
* @param null $markup |
|
384
|
|
|
* @param string $contentType |
|
385
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
386
|
|
|
*/ |
|
387
|
|
|
public static function newDocumentPHP($markup = null, $contentType = "text/html") |
|
388
|
|
|
{ |
|
389
|
|
|
// TODO pass charset to phpToMarkup if possible (use DOMDocumentWrapper function) |
|
390
|
|
|
$markup = PhpQuery::phpToMarkup($markup, self::$defaultCharset); |
|
391
|
|
|
return self::newDocument($markup, $contentType); |
|
392
|
|
|
} |
|
393
|
|
|
|
|
394
|
|
|
public static function phpToMarkup($php, $charset = 'utf-8') |
|
|
|
|
|
|
395
|
|
|
{ |
|
396
|
|
|
$regexes = array( |
|
397
|
|
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)<' |
|
398
|
|
|
. '?php?(.*?)(?:\\?>)([^\']*)\'@s', |
|
399
|
|
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)<' |
|
400
|
|
|
. '?php?(.*?)(?:\\?>)([^"]*)"@s', |
|
401
|
|
|
); |
|
402
|
|
|
foreach ($regexes as $regex) |
|
403
|
|
|
while (preg_match($regex, $php, $matches)) { |
|
404
|
|
|
$php = preg_replace_callback( |
|
405
|
|
|
$regex, |
|
406
|
|
|
// create_function('$m, $charset = "'.$charset.'"', |
|
|
|
|
|
|
407
|
|
|
// 'return $m[1].$m[2] |
|
408
|
|
|
// .htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset) |
|
|
|
|
|
|
409
|
|
|
// .$m[5].$m[2];' |
|
410
|
|
|
// ), |
|
411
|
|
|
array( |
|
412
|
|
|
'PhpQuery', |
|
413
|
|
|
'_phpToMarkupCallback' |
|
414
|
|
|
), |
|
415
|
|
|
$php |
|
416
|
|
|
); |
|
417
|
|
|
} |
|
418
|
|
|
$regex = '@(^|>[^<]*)+?(<\?php(.*?)(\?>))@s'; |
|
419
|
|
|
//preg_match_all($regex, $php, $matches); |
|
|
|
|
|
|
420
|
|
|
//var_dump($matches); |
|
421
|
|
|
$php = preg_replace($regex, '\\1<php><!-- \\3 --></php>', $php); |
|
422
|
|
|
return $php; |
|
423
|
|
|
} |
|
424
|
|
|
|
|
425
|
|
|
public static function _phpToMarkupCallback($m, $charset = 'utf-8') |
|
426
|
|
|
{ |
|
427
|
|
|
return $m[1] . $m[2] |
|
428
|
|
|
. htmlspecialchars( |
|
429
|
|
|
"<" . "?php" . $m[4] . "?" . ">", |
|
430
|
|
|
ENT_QUOTES |
|
431
|
|
|
| ENT_NOQUOTES, |
|
432
|
|
|
$charset |
|
433
|
|
|
) . $m[5] . $m[2]; |
|
434
|
|
|
} |
|
435
|
|
|
|
|
436
|
|
|
public static function _markupToPHPCallback($m) |
|
437
|
|
|
{ |
|
438
|
|
|
return "<" . "?php " . htmlspecialchars_decode($m[1]) . " ?" . ">"; |
|
439
|
|
|
} |
|
440
|
|
|
|
|
441
|
|
|
/** |
|
442
|
|
|
* Converts document markup containing PHP code generated by PhpQuery::php() |
|
443
|
|
|
* into valid (executable) PHP code syntax. |
|
444
|
|
|
* |
|
445
|
|
|
* @param string|PhpQueryObject $content |
|
446
|
|
|
* @return string PHP code. |
|
447
|
|
|
*/ |
|
448
|
|
|
public static function markupToPHP($content) |
|
449
|
|
|
{ |
|
450
|
|
|
if ($content instanceof PhpQueryObject) |
|
451
|
|
|
$content = $content->markupOuter(); |
|
452
|
|
|
/* <php>...</php> to <?php...? > */ |
|
453
|
|
|
$content = preg_replace_callback( |
|
454
|
|
|
'@<php>\s*<!--(.*?)-->\s*</php>@s', |
|
455
|
|
|
// create_function('$m', |
|
456
|
|
|
// 'return "<'.'?php ".htmlspecialchars_decode($m[1])." ?'.'>";' |
|
|
|
|
|
|
457
|
|
|
// ), |
|
458
|
|
|
array( |
|
459
|
|
|
'PhpQuery', |
|
460
|
|
|
'_markupToPHPCallback' |
|
461
|
|
|
), |
|
462
|
|
|
$content |
|
463
|
|
|
); |
|
464
|
|
|
/* <node attr='< ?php ? >'> extra space added to save highlighters */ |
|
465
|
|
|
$regexes = array( |
|
466
|
|
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^\']*)\'@s', |
|
467
|
|
|
'@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^"]*)"@s', |
|
468
|
|
|
); |
|
469
|
|
|
foreach ($regexes as $regex) |
|
470
|
|
|
while (preg_match($regex, $content)) |
|
471
|
|
|
$content = preg_replace_callback( |
|
472
|
|
|
$regex, |
|
473
|
|
|
create_function( |
|
|
|
|
|
|
474
|
|
|
'$m', |
|
475
|
|
|
'return $m[1].$m[2].$m[3]."<?php " |
|
476
|
|
|
.str_replace( |
|
477
|
|
|
array("%20", "%3E", "%09", " ", "	", "%7B", "%24", "%7D", "%22", "%5B", "%5D"), |
|
478
|
|
|
array(" ", ">", " ", "\n", " ", "{", "$", "}", \'"\', "[", "]"), |
|
479
|
|
|
htmlspecialchars_decode($m[4]) |
|
480
|
|
|
) |
|
481
|
|
|
." ?>".$m[5].$m[2];' |
|
482
|
|
|
), |
|
483
|
|
|
$content |
|
484
|
|
|
); |
|
485
|
|
|
return $content; |
|
486
|
|
|
} |
|
487
|
|
|
|
|
488
|
|
|
/** |
|
489
|
|
|
* Creates new document from file $file. |
|
490
|
|
|
* Chainable. |
|
491
|
|
|
* |
|
492
|
|
|
* @param string $file URLs allowed. See File wrapper page at php.net for more supported sources. |
|
493
|
|
|
* @param null $contentType |
|
494
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
495
|
|
|
*/ |
|
496
|
|
|
public static function newDocumentFile($file, $contentType = null) |
|
497
|
|
|
{ |
|
498
|
|
|
$documentID = self::createDocumentWrapper(file_get_contents($file), $contentType); |
|
499
|
|
|
return new PhpQueryObject($documentID); |
|
500
|
|
|
} |
|
501
|
|
|
|
|
502
|
|
|
/** |
|
503
|
|
|
* Creates new document from markup. |
|
504
|
|
|
* Chainable. |
|
505
|
|
|
* |
|
506
|
|
|
* @param $file |
|
507
|
|
|
* @param null $charset |
|
508
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
509
|
|
|
*/ |
|
510
|
|
|
public static function newDocumentFileHTML($file, $charset = null) |
|
511
|
|
|
{ |
|
512
|
|
|
$contentType = $charset ? ";charset=$charset" : ''; |
|
513
|
|
|
return self::newDocumentFile($file, "text/html{$contentType}"); |
|
514
|
|
|
} |
|
515
|
|
|
|
|
516
|
|
|
/** |
|
517
|
|
|
* Creates new document from markup. |
|
518
|
|
|
* Chainable. |
|
519
|
|
|
* |
|
520
|
|
|
* @param $file |
|
521
|
|
|
* @param null $charset |
|
522
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
523
|
|
|
*/ |
|
524
|
|
|
public static function newDocumentFileXML($file, $charset = null) |
|
525
|
|
|
{ |
|
526
|
|
|
$contentType = $charset ? ";charset=$charset" : ''; |
|
527
|
|
|
return self::newDocumentFile($file, "text/xml{$contentType}"); |
|
528
|
|
|
} |
|
529
|
|
|
|
|
530
|
|
|
/** |
|
531
|
|
|
* Creates new document from markup. |
|
532
|
|
|
* Chainable. |
|
533
|
|
|
* |
|
534
|
|
|
* @param $file |
|
535
|
|
|
* @param null $charset |
|
536
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
537
|
|
|
*/ |
|
538
|
|
|
public static function newDocumentFileXHTML($file, $charset = null) |
|
539
|
|
|
{ |
|
540
|
|
|
$contentType = $charset ? ";charset=$charset" : ''; |
|
541
|
|
|
return self::newDocumentFile($file, "application/xhtml+xml{$contentType}"); |
|
542
|
|
|
} |
|
543
|
|
|
|
|
544
|
|
|
/** |
|
545
|
|
|
* Creates new document from markup. |
|
546
|
|
|
* Chainable. |
|
547
|
|
|
* |
|
548
|
|
|
* @param $file |
|
549
|
|
|
* @param null $contentType |
|
550
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
551
|
|
|
*/ |
|
552
|
|
|
public static function newDocumentFilePHP($file, $contentType = null) |
|
553
|
|
|
{ |
|
554
|
|
|
return self::newDocumentPHP(file_get_contents($file), $contentType); |
|
555
|
|
|
} |
|
556
|
|
|
|
|
557
|
|
|
/** |
|
558
|
|
|
* Reuses existing \DOMDocument object. |
|
559
|
|
|
* Chainable. |
|
560
|
|
|
* |
|
561
|
|
|
* @param $document \DOMDocument |
|
562
|
|
|
* @return PhpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery |
|
563
|
|
|
* @TODO support \DOMDocument |
|
564
|
|
|
*/ |
|
565
|
|
|
public static function loadDocument($document) |
|
|
|
|
|
|
566
|
|
|
{ |
|
567
|
|
|
// TODO |
|
568
|
|
|
die('TODO loadDocument'); |
|
|
|
|
|
|
569
|
|
|
} |
|
570
|
|
|
|
|
571
|
|
|
/** |
|
572
|
|
|
* Enter description here... |
|
573
|
|
|
* |
|
574
|
|
|
* @param $html |
|
575
|
|
|
* @param null $contentType |
|
576
|
|
|
* @param null $documentID |
|
577
|
|
|
* @return null|string |
|
578
|
|
|
* @throws \Exception |
|
579
|
|
|
* @todo support PHP tags in input |
|
580
|
|
|
* @todo support passing \DOMDocument object from self::loadDocument |
|
581
|
|
|
*/ |
|
582
|
|
|
protected static function createDocumentWrapper($html, $contentType = null, $documentID = null) |
|
583
|
|
|
{ |
|
584
|
|
|
if (function_exists('domxml_open_mem')) |
|
585
|
|
|
throw new \Exception("Old PHP4 DOM XML extension detected. PhpQuery won't work until this extension is enabled."); |
|
586
|
|
|
// $id = $documentID |
|
587
|
|
|
// ? $documentID |
|
588
|
|
|
// : md5(microtime()); |
|
|
|
|
|
|
589
|
|
|
$document = null; |
|
|
|
|
|
|
590
|
|
|
if ($html instanceof \DOMDocument) { |
|
591
|
|
|
if (self::getDocumentID($html)) { |
|
592
|
|
|
// document already exists in PhpQuery::$documents, make a copy |
|
593
|
|
|
$document = clone $html; |
|
|
|
|
|
|
594
|
|
|
} else { |
|
595
|
|
|
// new document, add it to PhpQuery::$documents |
|
596
|
|
|
$wrapper = new Dom\DOMDocumentWrapper($html, $contentType, $documentID); |
|
597
|
|
|
} |
|
598
|
|
|
} else { |
|
599
|
|
|
$wrapper = new Dom\DOMDocumentWrapper($html, $contentType, $documentID); |
|
600
|
|
|
} |
|
601
|
|
|
// $wrapper->id = $id; |
|
|
|
|
|
|
602
|
|
|
// bind document |
|
603
|
|
|
PhpQuery::$documents[$wrapper->id] = $wrapper; |
|
|
|
|
|
|
604
|
|
|
// remember last loaded document |
|
605
|
|
|
PhpQuery::selectDocument($wrapper->id); |
|
606
|
|
|
return $wrapper->id; |
|
607
|
|
|
} |
|
608
|
|
|
|
|
609
|
|
|
/** |
|
610
|
|
|
* Extend class namespace. |
|
611
|
|
|
* |
|
612
|
|
|
* @param string|array $target |
|
613
|
|
|
* @param array $source |
|
614
|
|
|
* @throws \Exception |
|
615
|
|
|
* @return bool |
|
616
|
|
|
* @TODO support string $source |
|
617
|
|
|
*/ |
|
618
|
|
|
public static function extend($target, $source) |
|
619
|
|
|
{ |
|
620
|
|
|
switch ($target) { |
|
621
|
|
|
case 'PhpQueryObject': |
|
622
|
|
|
$targetRef = & self::$extendMethods; |
|
623
|
|
|
$targetRef2 = & self::$pluginsMethods; |
|
624
|
|
|
break; |
|
625
|
|
|
case 'PhpQuery': |
|
626
|
|
|
$targetRef = & self::$extendStaticMethods; |
|
627
|
|
|
$targetRef2 = & self::$pluginsStaticMethods; |
|
628
|
|
|
break; |
|
629
|
|
|
default: |
|
630
|
|
|
throw new \Exception("Unsupported \$target type"); |
|
631
|
|
|
} |
|
632
|
|
|
if (is_string($source)) |
|
633
|
|
|
$source = array( |
|
634
|
|
|
$source => $source |
|
635
|
|
|
); |
|
636
|
|
|
foreach ($source as $method => $callback) { |
|
637
|
|
|
if (isset($targetRef[$method])) { |
|
638
|
|
|
// throw new \Exception |
|
639
|
|
|
self::debug("Duplicate method '{$method}', can\'t extend '{$target}'"); |
|
640
|
|
|
continue; |
|
641
|
|
|
} |
|
642
|
|
|
if (isset($targetRef2[$method])) { |
|
643
|
|
|
// throw new \Exception |
|
644
|
|
|
self::debug( |
|
645
|
|
|
"Duplicate method '{$method}' from plugin '{$targetRef2[$method]}'," |
|
646
|
|
|
. " can\'t extend '{$target}'" |
|
647
|
|
|
); |
|
648
|
|
|
continue; |
|
649
|
|
|
} |
|
650
|
|
|
$targetRef[$method] = $callback; |
|
651
|
|
|
} |
|
652
|
|
|
return true; |
|
653
|
|
|
} |
|
654
|
|
|
|
|
655
|
|
|
/** |
|
656
|
|
|
* Extend PhpQuery with $class from $file. |
|
657
|
|
|
* |
|
658
|
|
|
* @param string $class Extending class name. Real class name can be prepended PhpQuery_. |
|
659
|
|
|
* @param string $file Filename to include. Defaults to "{$class}.php". |
|
660
|
|
|
* @throws \Exception |
|
661
|
|
|
* @return bool |
|
662
|
|
|
*/ |
|
663
|
|
|
public static function plugin($class, $file = null) |
|
664
|
|
|
{ |
|
665
|
|
|
// TODO $class checked agains PhpQuery_$class |
|
666
|
|
|
// if (strpos($class, 'PhpQuery') === 0) |
|
|
|
|
|
|
667
|
|
|
// $class = substr($class, 8); |
|
|
|
|
|
|
668
|
|
|
if (in_array($class, self::$pluginsLoaded)) |
|
669
|
|
|
return true; |
|
670
|
|
|
if (!$file) |
|
|
|
|
|
|
671
|
|
|
$file = $class . '.php'; |
|
672
|
|
|
$objectClassExists = class_exists('\\PhpQuery\\Plugin\\' . $class); |
|
673
|
|
|
$staticClassExists = class_exists('\PhpQuery\Plugin\Util' . $class); |
|
674
|
|
|
if (!$objectClassExists && !$staticClassExists) |
|
675
|
|
|
require_once($file); |
|
676
|
|
|
self::$pluginsLoaded[] = $class; |
|
677
|
|
|
// static methods |
|
678
|
|
|
if (class_exists('\PhpQuery\Plugin\Util' . $class)) { |
|
679
|
|
|
$realClass = '\PhpQuery\Plugin\Util' . $class; |
|
680
|
|
|
$vars = get_class_vars($realClass); |
|
681
|
|
|
$loop = isset($vars['PhpQueryMethods']) |
|
682
|
|
|
&& !is_null($vars['PhpQueryMethods']) ? $vars['PhpQueryMethods'] |
|
683
|
|
|
: get_class_methods($realClass); |
|
684
|
|
View Code Duplication |
foreach ($loop as $method) { |
|
|
|
|
|
|
685
|
|
|
if ($method == '__initialize') |
|
686
|
|
|
continue; |
|
687
|
|
|
if (!is_callable( |
|
688
|
|
|
array( |
|
689
|
|
|
$realClass, |
|
690
|
|
|
$method |
|
691
|
|
|
) |
|
692
|
|
|
) |
|
693
|
|
|
) |
|
694
|
|
|
continue; |
|
695
|
|
|
if (isset(self::$pluginsStaticMethods[$method])) { |
|
696
|
|
|
throw new \Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '" |
|
697
|
|
|
. self::$pluginsStaticMethods[$method] . "'"); |
|
698
|
|
|
} |
|
699
|
|
|
self::$pluginsStaticMethods[$method] = $class; |
|
700
|
|
|
} |
|
701
|
|
|
if (method_exists($realClass, '__initialize')) |
|
702
|
|
|
call_user_func_array( |
|
703
|
|
|
array( |
|
704
|
|
|
$realClass, |
|
705
|
|
|
'__initialize' |
|
706
|
|
|
), |
|
707
|
|
|
array() |
|
708
|
|
|
); |
|
709
|
|
|
} |
|
710
|
|
|
// object methods |
|
711
|
|
|
if (class_exists('\\PhpQuery\\Plugin\\' . $class)) { |
|
712
|
|
|
$realClass = '\\PhpQuery\\Plugin\\' . $class; |
|
713
|
|
|
$vars = get_class_vars($realClass); |
|
714
|
|
|
$loop = isset($vars['PhpQueryMethods']) |
|
715
|
|
|
&& !is_null($vars['PhpQueryMethods']) ? $vars['PhpQueryMethods'] |
|
716
|
|
|
: get_class_methods($realClass); |
|
717
|
|
View Code Duplication |
foreach ($loop as $method) { |
|
|
|
|
|
|
718
|
|
|
if (!is_callable( |
|
719
|
|
|
array( |
|
720
|
|
|
$realClass, |
|
721
|
|
|
$method |
|
722
|
|
|
) |
|
723
|
|
|
) |
|
724
|
|
|
) |
|
725
|
|
|
continue; |
|
726
|
|
|
if (isset(self::$pluginsMethods[$method])) { |
|
727
|
|
|
throw new \Exception("Duplicate method '{$method}' from plugin '{$class}' conflicts with same method from plugin '" |
|
728
|
|
|
. self::$pluginsMethods[$method] . "'"); |
|
729
|
|
|
continue; |
|
|
|
|
|
|
730
|
|
|
} |
|
731
|
|
|
self::$pluginsMethods[$method] = $class; |
|
732
|
|
|
} |
|
733
|
|
|
} |
|
734
|
|
|
return true; |
|
735
|
|
|
} |
|
736
|
|
|
|
|
737
|
|
|
/** |
|
738
|
|
|
* Unloades all or specified document from memory. |
|
739
|
|
|
* |
|
740
|
|
|
* @param null $id |
|
741
|
|
|
* @internal param mixed $documentID @see PhpQuery::getDocumentID() for supported types. |
|
742
|
|
|
*/ |
|
743
|
|
|
public static function unloadDocuments($id = null) |
|
744
|
|
|
{ |
|
745
|
|
|
if (isset($id)) { |
|
746
|
|
|
if ($id = self::getDocumentID($id)) |
|
747
|
|
|
unset(PhpQuery::$documents[$id]); |
|
748
|
|
|
} else { |
|
749
|
|
|
foreach (PhpQuery::$documents as $k => $v) { |
|
750
|
|
|
unset(PhpQuery::$documents[$k]); |
|
751
|
|
|
} |
|
752
|
|
|
} |
|
753
|
|
|
} |
|
754
|
|
|
|
|
755
|
|
|
/** |
|
756
|
|
|
* Parses PhpQuery object or HTML result against PHP tags and makes them active. |
|
757
|
|
|
* |
|
758
|
|
|
* @param PhpQuery|string $content |
|
759
|
|
|
* @deprecated |
|
760
|
|
|
* @return string |
|
761
|
|
|
*/ |
|
762
|
|
|
public static function unsafePHPTags($content) |
|
763
|
|
|
{ |
|
764
|
|
|
return self::markupToPHP($content); |
|
|
|
|
|
|
765
|
|
|
} |
|
766
|
|
|
|
|
767
|
|
|
public static function DOMNodeListToArray($DOMNodeList) |
|
768
|
|
|
{ |
|
769
|
|
|
$array = array(); |
|
770
|
|
|
if (!$DOMNodeList) |
|
771
|
|
|
return $array; |
|
772
|
|
|
foreach ($DOMNodeList as $node) |
|
773
|
|
|
$array[] = $node; |
|
774
|
|
|
return $array; |
|
775
|
|
|
} |
|
776
|
|
|
|
|
777
|
|
|
/** |
|
778
|
|
|
* Checks if $input is HTML string, which has to start with '<'. |
|
779
|
|
|
* |
|
780
|
|
|
* @deprecated |
|
781
|
|
|
* @param String $input |
|
782
|
|
|
* @return Bool |
|
783
|
|
|
* @todo still used ? |
|
784
|
|
|
*/ |
|
785
|
|
|
public static function isMarkup($input) |
|
786
|
|
|
{ |
|
787
|
|
|
return is_string($input) && substr(trim($input), 0, 1) == '<'; |
|
788
|
|
|
} |
|
789
|
|
|
|
|
790
|
|
|
public static function debug($text) |
|
791
|
|
|
{ |
|
792
|
|
|
if (self::$debug) |
|
793
|
|
|
print var_dump($text); |
|
|
|
|
|
|
794
|
|
|
} |
|
795
|
|
|
|
|
796
|
|
|
/** |
|
797
|
|
|
* Make an AJAX request. |
|
798
|
|
|
* |
|
799
|
|
|
* @param array $options |
|
800
|
|
|
* @param null $xhr |
|
801
|
|
|
* @throws \Exception |
|
802
|
|
|
* @internal param \PhpQuery\See $array $options http://docs.jquery.com/Ajax/jQuery.ajax#toptions |
|
803
|
|
|
* Additional options are: |
|
804
|
|
|
* 'document' - document for global events, @see PhpQuery::getDocumentID() |
|
805
|
|
|
* 'referer' - implemented |
|
806
|
|
|
* 'requested_with' - TODO; not implemented (X-Requested-With) |
|
807
|
|
|
* @return \Zend_Http_Client |
|
808
|
|
|
* @link http://docs.jquery.com/Ajax/jQuery.ajax |
|
809
|
|
|
* |
|
810
|
|
|
* @TODO $options['cache'] |
|
811
|
|
|
* @TODO $options['processData'] |
|
812
|
|
|
* @TODO $options['xhr'] |
|
813
|
|
|
* @TODO $options['data'] as string |
|
814
|
|
|
* @TODO XHR interface |
|
815
|
|
|
*/ |
|
816
|
|
|
public static function ajax($options = array(), $xhr = null) |
|
|
|
|
|
|
817
|
|
|
{ |
|
818
|
|
|
$options = array_merge(self::$ajaxSettings, $options); |
|
819
|
|
|
$documentID = isset($options['document']) ? self::getDocumentID($options['document']) |
|
820
|
|
|
: null; |
|
821
|
|
|
if ($xhr) { |
|
822
|
|
|
// reuse existing XHR object, but clean it up |
|
823
|
|
|
$client = $xhr; |
|
824
|
|
|
// $client->setParameterPost(null); |
|
|
|
|
|
|
825
|
|
|
// $client->setParameterGet(null); |
|
|
|
|
|
|
826
|
|
|
$client->setAuth(false); |
|
827
|
|
|
$client->setHeaders("If-Modified-Since", null); |
|
828
|
|
|
$client->setHeaders("Referer", null); |
|
829
|
|
|
$client->resetParameters(); |
|
830
|
|
|
} else { |
|
831
|
|
|
// create new XHR object |
|
832
|
|
|
$client = new \Zend_Http_Client(); |
|
833
|
|
|
$client->setCookieJar(); |
|
834
|
|
|
} |
|
835
|
|
|
if (isset($options['timeout'])) |
|
836
|
|
|
$client->setConfig( |
|
837
|
|
|
array( |
|
838
|
|
|
'timeout' => $options['timeout'], |
|
839
|
|
|
) |
|
840
|
|
|
); |
|
841
|
|
|
// 'maxredirects' => 0, |
|
|
|
|
|
|
842
|
|
|
foreach (self::$ajaxAllowedHosts as $k => $host) |
|
843
|
|
|
if ($host == '.' && isset($_SERVER['HTTP_HOST'])) |
|
844
|
|
|
self::$ajaxAllowedHosts[$k] = $_SERVER['HTTP_HOST']; |
|
845
|
|
|
$host = parse_url($options['url'], PHP_URL_HOST); |
|
846
|
|
|
if (!in_array($host, self::$ajaxAllowedHosts)) { |
|
847
|
|
|
throw new \Exception("Request not permitted, host '$host' not present in " |
|
848
|
|
|
. "PhpQuery::\$ajaxAllowedHosts"); |
|
849
|
|
|
} |
|
850
|
|
|
// JSONP |
|
851
|
|
|
$jsre = "/=\\?(&|$)/"; |
|
852
|
|
|
if (isset($options['dataType']) && $options['dataType'] == 'jsonp') { |
|
853
|
|
|
$jsonpCallbackParam = $options['jsonp'] ? $options['jsonp'] : 'callback'; |
|
854
|
|
|
if (strtolower($options['type']) == 'get') { |
|
855
|
|
|
if (!preg_match($jsre, $options['url'])) { |
|
856
|
|
|
$sep = strpos($options['url'], '?') ? '&' : '?'; |
|
857
|
|
|
$options['url'] .= "$sep$jsonpCallbackParam=?"; |
|
858
|
|
|
} |
|
859
|
|
|
} else if ($options['data']) { |
|
860
|
|
|
$jsonp = false; |
|
861
|
|
|
foreach ($options['data'] as $n => $v) { |
|
862
|
|
|
if ($v == '?') |
|
863
|
|
|
$jsonp = true; |
|
864
|
|
|
} |
|
865
|
|
|
if (!$jsonp) { |
|
866
|
|
|
$options['data'][$jsonpCallbackParam] = '?'; |
|
867
|
|
|
} |
|
868
|
|
|
} |
|
869
|
|
|
$options['dataType'] = 'json'; |
|
870
|
|
|
} |
|
871
|
|
|
if (isset($options['dataType']) && $options['dataType'] == 'json') { |
|
872
|
|
|
$jsonpCallback = 'json_' . md5(microtime()); |
|
873
|
|
|
$jsonpData = $jsonpUrl = false; |
|
874
|
|
|
if ($options['data']) { |
|
875
|
|
|
foreach ($options['data'] as $n => $v) { |
|
876
|
|
|
if ($v == '?') |
|
877
|
|
|
$jsonpData = $n; |
|
878
|
|
|
} |
|
879
|
|
|
} |
|
880
|
|
|
if (preg_match($jsre, $options['url'])) |
|
881
|
|
|
$jsonpUrl = true; |
|
882
|
|
|
if ($jsonpData !== false || $jsonpUrl) { |
|
883
|
|
|
// remember callback name for httpData() |
|
884
|
|
|
$options['_jsonp'] = $jsonpCallback; |
|
885
|
|
|
if ($jsonpData !== false) |
|
886
|
|
|
$options['data'][$jsonpData] = $jsonpCallback; |
|
887
|
|
|
if ($jsonpUrl) |
|
888
|
|
|
$options['url'] = preg_replace($jsre, "=$jsonpCallback\\1", $options['url']); |
|
889
|
|
|
} |
|
890
|
|
|
} |
|
891
|
|
|
$client->setUri($options['url']); |
|
892
|
|
|
$client->setMethod(strtoupper($options['type'])); |
|
893
|
|
|
if (isset($options['referer']) && $options['referer']) |
|
894
|
|
|
$client->setHeaders('Referer', $options['referer']); |
|
895
|
|
|
$client->setHeaders( |
|
896
|
|
|
array( |
|
897
|
|
|
// 'content-type' => $options['contentType'], |
|
|
|
|
|
|
898
|
|
|
'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86; en-US; rv:1.9.0.5) Gecko' |
|
899
|
|
|
. '/2008122010 Firefox/3.0.5', |
|
900
|
|
|
// TODO custom charset |
|
901
|
|
|
'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', |
|
902
|
|
|
// 'Connection' => 'keep-alive', |
|
|
|
|
|
|
903
|
|
|
// 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', |
|
|
|
|
|
|
904
|
|
|
'Accept-Language' => 'en-us,en;q=0.5', |
|
905
|
|
|
) |
|
906
|
|
|
); |
|
907
|
|
|
if ($options['username']) |
|
908
|
|
|
$client->setAuth($options['username'], $options['password']); |
|
909
|
|
|
if (isset($options['ifModified']) && $options['ifModified']) |
|
910
|
|
|
$client->setHeaders( |
|
911
|
|
|
"If-Modified-Since", |
|
912
|
|
|
self::$lastModified ? self::$lastModified |
|
913
|
|
|
: "Thu, 01 Jan 1970 00:00:00 GMT" |
|
914
|
|
|
); |
|
915
|
|
|
$client->setHeaders( |
|
916
|
|
|
"Accept", |
|
917
|
|
|
isset($options['dataType']) |
|
918
|
|
|
&& isset(self::$ajaxSettings['accepts'][$options['dataType']]) ? self::$ajaxSettings['accepts'][$options['dataType']] |
|
919
|
|
|
. ", */*" : self::$ajaxSettings['accepts']['_default'] |
|
920
|
|
|
); |
|
921
|
|
|
// TODO $options['processData'] |
|
|
|
|
|
|
922
|
|
|
if ($options['data'] instanceof PhpQueryObject) { |
|
923
|
|
|
$serialized = $options['data']->serializeArray($options['data']); |
|
924
|
|
|
$options['data'] = array(); |
|
925
|
|
|
foreach ($serialized as $r) |
|
926
|
|
|
$options['data'][$r['name']] = $r['value']; |
|
927
|
|
|
} |
|
928
|
|
|
if (strtolower($options['type']) == 'get') { |
|
929
|
|
|
$client->setParameterGet($options['data']); |
|
930
|
|
|
} else if (strtolower($options['type']) == 'post') { |
|
931
|
|
|
$client->setEncType($options['contentType']); |
|
932
|
|
|
$client->setParameterPost($options['data']); |
|
933
|
|
|
} |
|
934
|
|
|
if (self::$active == 0 && $options['global']) |
|
935
|
|
|
PhpQueryEvents::trigger($documentID, 'ajaxStart'); |
|
936
|
|
|
self::$active++; |
|
937
|
|
|
// beforeSend callback |
|
938
|
|
|
if (isset($options['beforeSend']) && $options['beforeSend']) |
|
939
|
|
|
PhpQuery::callbackRun( |
|
940
|
|
|
$options['beforeSend'], |
|
941
|
|
|
array( |
|
942
|
|
|
$client |
|
943
|
|
|
) |
|
944
|
|
|
); |
|
945
|
|
|
// ajaxSend event |
|
946
|
|
|
if ($options['global']) |
|
947
|
|
|
PhpQueryEvents::trigger( |
|
948
|
|
|
$documentID, |
|
949
|
|
|
'ajaxSend', |
|
950
|
|
|
array( |
|
951
|
|
|
$client, |
|
952
|
|
|
$options |
|
953
|
|
|
) |
|
954
|
|
|
); |
|
955
|
|
|
if (PhpQuery::$debug) { |
|
956
|
|
|
self::debug("{$options['type']}: {$options['url']}\n"); |
|
957
|
|
|
self::debug("Options: <pre>" . var_export($options, true) . "</pre>\n"); |
|
958
|
|
|
// if ($client->getCookieJar()) |
|
|
|
|
|
|
959
|
|
|
// self::debug("Cookies: <pre>".var_export($client->getCookieJar()->getMatchingCookies($options['url']), true)."</pre>\n"); |
|
|
|
|
|
|
960
|
|
|
} |
|
961
|
|
|
// request |
|
962
|
|
|
$response = $client->request(); |
|
963
|
|
|
if (PhpQuery::$debug) { |
|
964
|
|
|
self::debug( |
|
965
|
|
|
'Status: ' . $response->getStatus() . ' / ' |
|
966
|
|
|
. $response->getMessage() |
|
967
|
|
|
); |
|
968
|
|
|
self::debug($client->getLastRequest()); |
|
969
|
|
|
self::debug($response->getHeaders()); |
|
970
|
|
|
} |
|
971
|
|
|
if ($response->isSuccessful()) { |
|
972
|
|
|
// XXX tempolary |
|
973
|
|
|
self::$lastModified = $response->getHeader('Last-Modified'); |
|
974
|
|
|
$data = self::httpData($response->getBody(), $options['dataType'], $options); |
|
975
|
|
View Code Duplication |
if (isset($options['success']) && $options['success']) |
|
|
|
|
|
|
976
|
|
|
PhpQuery::callbackRun( |
|
977
|
|
|
$options['success'], |
|
978
|
|
|
array( |
|
979
|
|
|
$data, |
|
980
|
|
|
$response->getStatus(), |
|
981
|
|
|
$options |
|
982
|
|
|
) |
|
983
|
|
|
); |
|
984
|
|
|
if ($options['global']) |
|
985
|
|
|
PhpQueryEvents::trigger( |
|
986
|
|
|
$documentID, |
|
987
|
|
|
'ajaxSuccess', |
|
988
|
|
|
array( |
|
989
|
|
|
$client, |
|
990
|
|
|
$options |
|
991
|
|
|
) |
|
992
|
|
|
); |
|
993
|
|
|
} else { |
|
994
|
|
View Code Duplication |
if (isset($options['error']) && $options['error']) |
|
|
|
|
|
|
995
|
|
|
PhpQuery::callbackRun( |
|
996
|
|
|
$options['error'], |
|
997
|
|
|
array( |
|
998
|
|
|
$client, |
|
999
|
|
|
$response->getStatus(), |
|
1000
|
|
|
$response->getMessage() |
|
1001
|
|
|
) |
|
1002
|
|
|
); |
|
1003
|
|
|
if ($options['global']) |
|
1004
|
|
|
PhpQueryEvents::trigger( |
|
1005
|
|
|
$documentID, |
|
1006
|
|
|
'ajaxError', |
|
1007
|
|
|
array( |
|
1008
|
|
|
$client, |
|
1009
|
|
|
/*$response->getStatus(),*/ |
|
|
|
|
|
|
1010
|
|
|
$response->getMessage(), |
|
1011
|
|
|
$options |
|
1012
|
|
|
) |
|
1013
|
|
|
); |
|
1014
|
|
|
} |
|
1015
|
|
|
if (isset($options['complete']) && $options['complete']) |
|
1016
|
|
|
PhpQuery::callbackRun( |
|
1017
|
|
|
$options['complete'], |
|
1018
|
|
|
array( |
|
1019
|
|
|
$client, |
|
1020
|
|
|
$response->getStatus() |
|
1021
|
|
|
) |
|
1022
|
|
|
); |
|
1023
|
|
|
if ($options['global']) |
|
1024
|
|
|
PhpQueryEvents::trigger( |
|
1025
|
|
|
$documentID, |
|
1026
|
|
|
'ajaxComplete', |
|
1027
|
|
|
array( |
|
1028
|
|
|
$client, |
|
1029
|
|
|
$options |
|
1030
|
|
|
) |
|
1031
|
|
|
); |
|
1032
|
|
|
if ($options['global'] && !--self::$active) |
|
1033
|
|
|
PhpQueryEvents::trigger($documentID, 'ajaxStop'); |
|
1034
|
|
|
return $client; |
|
1035
|
|
|
// if (is_null($domId)) |
|
|
|
|
|
|
1036
|
|
|
// $domId = self::$defaultDocumentID ? self::$defaultDocumentID : false; |
|
|
|
|
|
|
1037
|
|
|
// return new PhpQueryAjaxResponse($response, $domId); |
|
|
|
|
|
|
1038
|
|
|
} |
|
1039
|
|
|
|
|
1040
|
|
|
protected static function httpData($data, $type, $options) |
|
1041
|
|
|
{ |
|
1042
|
|
View Code Duplication |
if (isset($options['dataFilter']) && $options['dataFilter']) |
|
|
|
|
|
|
1043
|
|
|
$data = self::callbackRun( |
|
1044
|
|
|
$options['dataFilter'], |
|
1045
|
|
|
array( |
|
1046
|
|
|
$data, |
|
1047
|
|
|
$type |
|
1048
|
|
|
) |
|
1049
|
|
|
); |
|
1050
|
|
|
if (is_string($data)) { |
|
1051
|
|
|
if ($type == "json") { |
|
1052
|
|
|
if (isset($options['_jsonp']) && $options['_jsonp']) { |
|
1053
|
|
|
$data = preg_replace('/^\s*\w+\((.*)\)\s*$/s', '$1', $data); |
|
1054
|
|
|
} |
|
1055
|
|
|
$data = self::parseJSON($data); |
|
1056
|
|
|
} |
|
1057
|
|
|
} |
|
1058
|
|
|
return $data; |
|
1059
|
|
|
} |
|
1060
|
|
|
|
|
1061
|
|
|
/** |
|
1062
|
|
|
* Enter description here... |
|
1063
|
|
|
* |
|
1064
|
|
|
* @param array|PhpQuery $data |
|
1065
|
|
|
* |
|
1066
|
|
|
* @return string |
|
1067
|
|
|
*/ |
|
1068
|
|
|
public static function param($data) |
|
1069
|
|
|
{ |
|
1070
|
|
|
return http_build_query($data, null, '&'); |
|
1071
|
|
|
} |
|
1072
|
|
|
|
|
1073
|
|
View Code Duplication |
public static function get($url, $data = null, $callback = null, $type = null) |
|
|
|
|
|
|
1074
|
|
|
{ |
|
1075
|
|
|
if (!is_array($data)) { |
|
1076
|
|
|
$callback = $data; |
|
1077
|
|
|
$data = null; |
|
1078
|
|
|
} |
|
1079
|
|
|
// TODO some array_values on this shit |
|
1080
|
|
|
return PhpQuery::ajax( |
|
1081
|
|
|
array( |
|
1082
|
|
|
'type' => 'GET', |
|
1083
|
|
|
'url' => $url, |
|
1084
|
|
|
'data' => $data, |
|
1085
|
|
|
'success' => $callback, |
|
1086
|
|
|
'dataType' => $type, |
|
1087
|
|
|
) |
|
1088
|
|
|
); |
|
1089
|
|
|
} |
|
1090
|
|
|
|
|
1091
|
|
View Code Duplication |
public static function post($url, $data = null, $callback = null, $type = null) |
|
|
|
|
|
|
1092
|
|
|
{ |
|
1093
|
|
|
if (!is_array($data)) { |
|
1094
|
|
|
$callback = $data; |
|
1095
|
|
|
$data = null; |
|
1096
|
|
|
} |
|
1097
|
|
|
return PhpQuery::ajax( |
|
1098
|
|
|
array( |
|
1099
|
|
|
'type' => 'POST', |
|
1100
|
|
|
'url' => $url, |
|
1101
|
|
|
'data' => $data, |
|
1102
|
|
|
'success' => $callback, |
|
1103
|
|
|
'dataType' => $type, |
|
1104
|
|
|
) |
|
1105
|
|
|
); |
|
1106
|
|
|
} |
|
1107
|
|
|
|
|
1108
|
|
View Code Duplication |
public static function getJSON($url, $data = null, $callback = null) |
|
|
|
|
|
|
1109
|
|
|
{ |
|
1110
|
|
|
if (!is_array($data)) { |
|
1111
|
|
|
$callback = $data; |
|
1112
|
|
|
$data = null; |
|
1113
|
|
|
} |
|
1114
|
|
|
// TODO some array_values on this shit |
|
1115
|
|
|
return PhpQuery::ajax( |
|
1116
|
|
|
array( |
|
1117
|
|
|
'type' => 'GET', |
|
1118
|
|
|
'url' => $url, |
|
1119
|
|
|
'data' => $data, |
|
1120
|
|
|
'success' => $callback, |
|
1121
|
|
|
'dataType' => 'json', |
|
1122
|
|
|
) |
|
1123
|
|
|
); |
|
1124
|
|
|
} |
|
1125
|
|
|
|
|
1126
|
|
|
public static function ajaxSetup($options) |
|
1127
|
|
|
{ |
|
1128
|
|
|
self::$ajaxSettings = array_merge(self::$ajaxSettings, $options); |
|
1129
|
|
|
} |
|
1130
|
|
|
|
|
1131
|
|
|
public static function ajaxAllowHost($host1, $host2 = null, $host3 = null) |
|
|
|
|
|
|
1132
|
|
|
{ |
|
1133
|
|
|
$loop = is_array($host1) ? $host1 : func_get_args(); |
|
1134
|
|
|
foreach ($loop as $host) { |
|
1135
|
|
|
if ($host && !in_array($host, PhpQuery::$ajaxAllowedHosts)) { |
|
1136
|
|
|
PhpQuery::$ajaxAllowedHosts[] = $host; |
|
1137
|
|
|
} |
|
1138
|
|
|
} |
|
1139
|
|
|
} |
|
1140
|
|
|
|
|
1141
|
|
|
public static function ajaxAllowURL($url1, $url2 = null, $url3 = null) |
|
|
|
|
|
|
1142
|
|
|
{ |
|
1143
|
|
|
$loop = is_array($url1) ? $url1 : func_get_args(); |
|
1144
|
|
|
foreach ($loop as $url) |
|
1145
|
|
|
PhpQuery::ajaxAllowHost(parse_url($url, PHP_URL_HOST)); |
|
1146
|
|
|
} |
|
1147
|
|
|
|
|
1148
|
|
|
/** |
|
1149
|
|
|
* Returns JSON representation of $data. |
|
1150
|
|
|
* |
|
1151
|
|
|
* @static |
|
1152
|
|
|
* @param mixed $data |
|
1153
|
|
|
* @return string |
|
1154
|
|
|
*/ |
|
1155
|
|
|
public static function toJSON($data) |
|
1156
|
|
|
{ |
|
1157
|
|
|
if (function_exists('json_encode')) |
|
1158
|
|
|
return json_encode($data); |
|
1159
|
|
|
require_once('Zend/Json/Encoder.php'); |
|
1160
|
|
|
return \Zend_Json_Encoder::encode($data); |
|
1161
|
|
|
} |
|
1162
|
|
|
|
|
1163
|
|
|
/** |
|
1164
|
|
|
* Parses JSON into proper PHP type. |
|
1165
|
|
|
* |
|
1166
|
|
|
* @static |
|
1167
|
|
|
* @param string $json |
|
1168
|
|
|
* @return mixed |
|
1169
|
|
|
*/ |
|
1170
|
|
|
public static function parseJSON($json) |
|
1171
|
|
|
{ |
|
1172
|
|
|
if (function_exists('json_decode')) { |
|
1173
|
|
|
$return = json_decode(trim($json), true); |
|
1174
|
|
|
// json_decode and UTF8 issues |
|
1175
|
|
|
if (isset($return)) |
|
1176
|
|
|
return $return; |
|
1177
|
|
|
} |
|
1178
|
|
|
require_once('Zend/Json/Decoder.php'); |
|
1179
|
|
|
return \Zend_Json_Decoder::decode($json); |
|
1180
|
|
|
} |
|
1181
|
|
|
|
|
1182
|
|
|
/** |
|
1183
|
|
|
* Returns source's document ID. |
|
1184
|
|
|
* |
|
1185
|
|
|
* @param $source \DOMNode|PhpQueryObject |
|
1186
|
|
|
* @return string |
|
1187
|
|
|
*/ |
|
1188
|
|
|
public static function getDocumentID($source) |
|
1189
|
|
|
{ |
|
1190
|
|
|
if ($source instanceof \DOMDocument) { |
|
1191
|
|
|
foreach (PhpQuery::$documents as $id => $document) { |
|
1192
|
|
|
if ($source->isSameNode($document->document)) |
|
1193
|
|
|
return $id; |
|
1194
|
|
|
} |
|
1195
|
|
|
} else if ($source instanceof \DOMNode) { |
|
1196
|
|
|
foreach (PhpQuery::$documents as $id => $document) { |
|
1197
|
|
|
if ($source->ownerDocument->isSameNode($document->document)) |
|
1198
|
|
|
return $id; |
|
1199
|
|
|
} |
|
1200
|
|
|
} else if ($source instanceof PhpQueryObject) |
|
1201
|
|
|
return $source->getDocumentID(); |
|
1202
|
|
|
else if (is_string($source) && isset(PhpQuery::$documents[$source])) |
|
1203
|
|
|
return $source; |
|
1204
|
|
|
} |
|
1205
|
|
|
|
|
1206
|
|
|
/** |
|
1207
|
|
|
* Get \DOMDocument object related to $source. |
|
1208
|
|
|
* Returns null if such document doesn't exist. |
|
1209
|
|
|
* |
|
1210
|
|
|
* @param $source \DOMNode|PhpQueryObject|string |
|
1211
|
|
|
* @return string |
|
1212
|
|
|
*/ |
|
1213
|
|
|
public static function getDOMDocument($source) |
|
1214
|
|
|
{ |
|
1215
|
|
|
if ($source instanceof \DOMDocument) |
|
1216
|
|
|
return $source; |
|
|
|
|
|
|
1217
|
|
|
$source = self::getDocumentID($source); |
|
1218
|
|
|
return $source ? self::$documents[$id]['document'] : null; |
|
|
|
|
|
|
1219
|
|
|
} |
|
1220
|
|
|
|
|
1221
|
|
|
// UTILITIES |
|
1222
|
|
|
// http://docs.jquery.com/Utilities |
|
1223
|
|
|
|
|
1224
|
|
|
/** |
|
1225
|
|
|
* |
|
1226
|
|
|
* @link http://docs.jquery.com/Utilities/jQuery.makeArray |
|
1227
|
|
|
* @param $object |
|
1228
|
|
|
* @return array |
|
1229
|
|
|
*/ |
|
1230
|
|
|
public static function makeArray($object) |
|
1231
|
|
|
{ |
|
1232
|
|
|
$array = array(); |
|
1233
|
|
|
if (is_object($object) && $object instanceof \DOMNodeList) { |
|
1234
|
|
|
foreach ($object as $value) |
|
1235
|
|
|
$array[] = $value; |
|
1236
|
|
|
} else if (is_object($object) && !($object instanceof \Iterator)) { |
|
1237
|
|
|
foreach (get_object_vars($object) as $name => $value) |
|
1238
|
|
|
$array[0][$name] = $value; |
|
1239
|
|
|
} else { |
|
1240
|
|
|
foreach ($object as $name => $value) |
|
1241
|
|
|
$array[0][$name] = $value; |
|
1242
|
|
|
} |
|
1243
|
|
|
return $array; |
|
1244
|
|
|
} |
|
1245
|
|
|
|
|
1246
|
|
|
public static function inArray($value, $array) |
|
1247
|
|
|
{ |
|
1248
|
|
|
return in_array($value, $array); |
|
1249
|
|
|
} |
|
1250
|
|
|
|
|
1251
|
|
|
/** |
|
1252
|
|
|
* |
|
1253
|
|
|
* @param $object |
|
1254
|
|
|
* @param $callback |
|
1255
|
|
|
* @param null $param1 |
|
1256
|
|
|
* @param null $param2 |
|
1257
|
|
|
* @param null $param3 |
|
1258
|
|
|
* @link http://docs.jquery.com/Utilities/jQuery.each |
|
1259
|
|
|
*/ |
|
1260
|
|
|
public static function each($object, $callback, $param1 = null, $param2 = null, $param3 = null) |
|
|
|
|
|
|
1261
|
|
|
{ |
|
1262
|
|
|
$paramStructure = null; |
|
1263
|
|
|
if (func_num_args() > 2) { |
|
1264
|
|
|
$paramStructure = func_get_args(); |
|
1265
|
|
|
$paramStructure = array_slice($paramStructure, 2); |
|
1266
|
|
|
} |
|
1267
|
|
|
if (is_object($object) && !($object instanceof \Iterator)) { |
|
1268
|
|
|
foreach (get_object_vars($object) as $name => $value) |
|
1269
|
|
|
PhpQuery::callbackRun( |
|
1270
|
|
|
$callback, |
|
1271
|
|
|
array( |
|
1272
|
|
|
$name, |
|
1273
|
|
|
$value |
|
1274
|
|
|
), |
|
1275
|
|
|
$paramStructure |
|
1276
|
|
|
); |
|
1277
|
|
|
} else { |
|
1278
|
|
|
foreach ($object as $name => $value) |
|
1279
|
|
|
PhpQuery::callbackRun( |
|
1280
|
|
|
$callback, |
|
1281
|
|
|
array( |
|
1282
|
|
|
$name, |
|
1283
|
|
|
$value |
|
1284
|
|
|
), |
|
1285
|
|
|
$paramStructure |
|
1286
|
|
|
); |
|
1287
|
|
|
} |
|
1288
|
|
|
} |
|
1289
|
|
|
|
|
1290
|
|
|
/** |
|
1291
|
|
|
* |
|
1292
|
|
|
* @link http://docs.jquery.com/Utilities/jQuery.map |
|
1293
|
|
|
*/ |
|
1294
|
|
|
public static function map($array, $callback, $param1 = null, $param2 = null, $param3 = null) |
|
|
|
|
|
|
1295
|
|
|
{ |
|
1296
|
|
|
$result = array(); |
|
1297
|
|
|
$paramStructure = null; |
|
1298
|
|
|
if (func_num_args() > 2) { |
|
1299
|
|
|
$paramStructure = func_get_args(); |
|
1300
|
|
|
$paramStructure = array_slice($paramStructure, 2); |
|
1301
|
|
|
} |
|
1302
|
|
View Code Duplication |
foreach ($array as $v) { |
|
|
|
|
|
|
1303
|
|
|
$vv = PhpQuery::callbackRun( |
|
1304
|
|
|
$callback, |
|
1305
|
|
|
array( |
|
1306
|
|
|
$v |
|
1307
|
|
|
), |
|
1308
|
|
|
$paramStructure |
|
1309
|
|
|
); |
|
1310
|
|
|
// $callbackArgs = $args; |
|
|
|
|
|
|
1311
|
|
|
// foreach($args as $i => $arg) { |
|
|
|
|
|
|
1312
|
|
|
// $callbackArgs[$i] = $arg instanceof CallbackParam |
|
|
|
|
|
|
1313
|
|
|
// ? $v |
|
1314
|
|
|
// : $arg; |
|
1315
|
|
|
// } |
|
1316
|
|
|
// $vv = call_user_func_array($callback, $callbackArgs); |
|
|
|
|
|
|
1317
|
|
|
if (is_array($vv)) { |
|
1318
|
|
|
foreach ($vv as $vvv) |
|
1319
|
|
|
$result[] = $vvv; |
|
1320
|
|
|
} else if ($vv !== null) { |
|
1321
|
|
|
$result[] = $vv; |
|
1322
|
|
|
} |
|
1323
|
|
|
} |
|
1324
|
|
|
return $result; |
|
1325
|
|
|
} |
|
1326
|
|
|
|
|
1327
|
|
|
/** |
|
1328
|
|
|
* |
|
1329
|
|
|
* @param $callback Callback |
|
1330
|
|
|
* @param $params |
|
1331
|
|
|
* @param $paramStructure |
|
1332
|
|
|
* @return bool|mixed |
|
1333
|
|
|
*/ |
|
1334
|
|
|
public static function callbackRun($callback, $params = array(), $paramStructure = null) |
|
1335
|
|
|
{ |
|
1336
|
|
|
if (!$callback) |
|
1337
|
|
|
return; |
|
1338
|
|
|
if ($callback instanceof \CallbackParameterToReference) { |
|
1339
|
|
|
// TODO support ParamStructure to select which $param push to reference |
|
1340
|
|
|
if (isset($params[0])) |
|
1341
|
|
|
$callback->callback = $params[0]; |
|
1342
|
|
|
return true; |
|
1343
|
|
|
} |
|
1344
|
|
|
if ($callback instanceof \Callback) { |
|
1345
|
|
|
$paramStructure = $callback->params; |
|
1346
|
|
|
$callback = $callback->callback; |
|
1347
|
|
|
} |
|
1348
|
|
|
if (!$paramStructure) |
|
1349
|
|
|
return call_user_func_array($callback, $params); |
|
|
|
|
|
|
1350
|
|
|
$p = 0; |
|
1351
|
|
|
foreach ($paramStructure as $i => $v) { |
|
1352
|
|
|
$paramStructure[$i] = $v instanceof \CallbackParam ? $params[$p++] : $v; |
|
1353
|
|
|
} |
|
1354
|
|
|
return call_user_func_array($callback, $paramStructure); |
|
|
|
|
|
|
1355
|
|
|
} |
|
1356
|
|
|
|
|
1357
|
|
|
/** |
|
1358
|
|
|
* Merge 2 PhpQuery objects. |
|
1359
|
|
|
* @param array $one |
|
1360
|
|
|
* @param array $two |
|
1361
|
|
|
* @return array |
|
1362
|
|
|
* @protected |
|
1363
|
|
|
* @todo node lists, PhpQueryObject |
|
1364
|
|
|
*/ |
|
1365
|
|
|
public static function merge($one, $two) |
|
1366
|
|
|
{ |
|
1367
|
|
|
$elements = $one->elements; |
|
1368
|
|
|
foreach ($two->elements as $node) { |
|
1369
|
|
|
$exists = false; |
|
1370
|
|
|
foreach ($elements as $node2) { |
|
1371
|
|
|
if ($node2->isSameNode($node)) |
|
1372
|
|
|
$exists = true; |
|
1373
|
|
|
} |
|
1374
|
|
|
if (!$exists) |
|
1375
|
|
|
$elements[] = $node; |
|
1376
|
|
|
} |
|
1377
|
|
|
return $elements; |
|
1378
|
|
|
// $one = $one->newInstance(); |
|
|
|
|
|
|
1379
|
|
|
// $one->elements = $elements; |
|
|
|
|
|
|
1380
|
|
|
// return $one; |
|
1381
|
|
|
} |
|
1382
|
|
|
|
|
1383
|
|
|
/** |
|
1384
|
|
|
* |
|
1385
|
|
|
* @param $array |
|
1386
|
|
|
* @param $callback |
|
1387
|
|
|
* @param $invert |
|
1388
|
|
|
* @return array |
|
1389
|
|
|
* @link http://docs.jquery.com/Utilities/jQuery.grep |
|
1390
|
|
|
*/ |
|
1391
|
|
|
public static function grep($array, $callback, $invert = false) |
|
1392
|
|
|
{ |
|
1393
|
|
|
$result = array(); |
|
1394
|
|
|
foreach ($array as $k => $v) { |
|
1395
|
|
|
$r = call_user_func_array( |
|
1396
|
|
|
$callback, |
|
1397
|
|
|
array( |
|
1398
|
|
|
$v, |
|
1399
|
|
|
$k |
|
1400
|
|
|
) |
|
1401
|
|
|
); |
|
1402
|
|
|
if ($r === !(bool) $invert) |
|
1403
|
|
|
$result[] = $v; |
|
1404
|
|
|
} |
|
1405
|
|
|
return $result; |
|
1406
|
|
|
} |
|
1407
|
|
|
|
|
1408
|
|
|
public static function unique($array) |
|
1409
|
|
|
{ |
|
1410
|
|
|
return array_unique($array); |
|
1411
|
|
|
} |
|
1412
|
|
|
|
|
1413
|
|
|
/** |
|
1414
|
|
|
* |
|
1415
|
|
|
* @param $function |
|
1416
|
|
|
* @return bool |
|
1417
|
|
|
* @TODO there are problems with non-static methods, second parameter pass it |
|
1418
|
|
|
* but doesnt verify is method is really callable |
|
1419
|
|
|
*/ |
|
1420
|
|
|
public static function isFunction($function) |
|
1421
|
|
|
{ |
|
1422
|
|
|
return is_callable($function); |
|
1423
|
|
|
} |
|
1424
|
|
|
|
|
1425
|
|
|
public static function trim($str) |
|
1426
|
|
|
{ |
|
1427
|
|
|
return trim($str); |
|
1428
|
|
|
} |
|
1429
|
|
|
/* PLUGINS NAMESPACE */ |
|
1430
|
|
|
/** |
|
1431
|
|
|
* |
|
1432
|
|
|
* @param $url |
|
1433
|
|
|
* @param $callback |
|
1434
|
|
|
* @param $param1 |
|
1435
|
|
|
* @param $param2 |
|
1436
|
|
|
* @param $param3 |
|
1437
|
|
|
* @return PhpQueryObject |
|
1438
|
|
|
*/ |
|
1439
|
|
View Code Duplication |
public static function browserGet($url, $callback, $param1 = null, $param2 = null, $param3 = null) |
|
|
|
|
|
|
1440
|
|
|
{ |
|
1441
|
|
|
if (self::plugin('WebBrowser')) { |
|
1442
|
|
|
$params = func_get_args(); |
|
1443
|
|
|
return self::callbackRun( |
|
1444
|
|
|
array( |
|
1445
|
|
|
self::$plugins, |
|
1446
|
|
|
'browserGet' |
|
1447
|
|
|
), |
|
1448
|
|
|
$params |
|
1449
|
|
|
); |
|
1450
|
|
|
} else { |
|
1451
|
|
|
self::debug('WebBrowser plugin not available...'); |
|
1452
|
|
|
} |
|
1453
|
|
|
} |
|
1454
|
|
|
|
|
1455
|
|
|
/** |
|
1456
|
|
|
* |
|
1457
|
|
|
* @param $url |
|
1458
|
|
|
* @param $data |
|
1459
|
|
|
* @param $callback |
|
1460
|
|
|
* @param $param1 |
|
1461
|
|
|
* @param $param2 |
|
1462
|
|
|
* @param $param3 |
|
1463
|
|
|
* @return PhpQueryObject |
|
1464
|
|
|
*/ |
|
1465
|
|
View Code Duplication |
public static function browserPost($url, $data, $callback, $param1 = null, $param2 = null, $param3 = null) |
|
|
|
|
|
|
1466
|
|
|
{ |
|
1467
|
|
|
if (self::plugin('WebBrowser')) { |
|
1468
|
|
|
$params = func_get_args(); |
|
1469
|
|
|
return self::callbackRun( |
|
1470
|
|
|
array( |
|
1471
|
|
|
self::$plugins, |
|
1472
|
|
|
'browserPost' |
|
1473
|
|
|
), |
|
1474
|
|
|
$params |
|
1475
|
|
|
); |
|
1476
|
|
|
} else { |
|
1477
|
|
|
self::debug('WebBrowser plugin not available...'); |
|
1478
|
|
|
} |
|
1479
|
|
|
} |
|
1480
|
|
|
|
|
1481
|
|
|
/** |
|
1482
|
|
|
* |
|
1483
|
|
|
* @param $ajaxSettings |
|
1484
|
|
|
* @param $callback |
|
1485
|
|
|
* @param $param1 |
|
1486
|
|
|
* @param $param2 |
|
1487
|
|
|
* @param $param3 |
|
1488
|
|
|
* @return PhpQueryObject |
|
1489
|
|
|
*/ |
|
1490
|
|
View Code Duplication |
public static function browser($ajaxSettings, $callback, $param1 = null, $param2 = null, $param3 = null) |
|
|
|
|
|
|
1491
|
|
|
{ |
|
1492
|
|
|
if (self::plugin('WebBrowser')) { |
|
1493
|
|
|
$params = func_get_args(); |
|
1494
|
|
|
return self::callbackRun( |
|
1495
|
|
|
array( |
|
1496
|
|
|
self::$plugins, |
|
1497
|
|
|
'browser' |
|
1498
|
|
|
), |
|
1499
|
|
|
$params |
|
1500
|
|
|
); |
|
1501
|
|
|
} else { |
|
1502
|
|
|
self::debug('WebBrowser plugin not available...'); |
|
1503
|
|
|
} |
|
1504
|
|
|
} |
|
1505
|
|
|
|
|
1506
|
|
|
/** |
|
1507
|
|
|
* |
|
1508
|
|
|
* @param $code |
|
1509
|
|
|
* @return string |
|
1510
|
|
|
*/ |
|
1511
|
|
|
public static function php($code) |
|
1512
|
|
|
{ |
|
1513
|
|
|
return self::code('php', $code); |
|
1514
|
|
|
} |
|
1515
|
|
|
|
|
1516
|
|
|
/** |
|
1517
|
|
|
* |
|
1518
|
|
|
* @param $type |
|
1519
|
|
|
* @param $code |
|
1520
|
|
|
* @return string |
|
1521
|
|
|
*/ |
|
1522
|
|
|
public static function code($type, $code) |
|
1523
|
|
|
{ |
|
1524
|
|
|
return "<$type><!-- " . trim($code) . " --></$type>"; |
|
1525
|
|
|
} |
|
1526
|
|
|
|
|
1527
|
|
|
public static function __callStatic($method, $params) |
|
1528
|
|
|
{ |
|
1529
|
|
|
return call_user_func_array( |
|
1530
|
|
|
array( |
|
1531
|
|
|
PhpQuery::$plugins, |
|
1532
|
|
|
$method |
|
1533
|
|
|
), |
|
1534
|
|
|
$params |
|
1535
|
|
|
); |
|
1536
|
|
|
} |
|
1537
|
|
|
|
|
1538
|
|
|
protected static function dataSetupNode($node, $documentID) |
|
1539
|
|
|
{ |
|
1540
|
|
|
// search are return if alredy exists |
|
1541
|
|
|
foreach (PhpQuery::$documents[$documentID]->dataNodes as $dataNode) { |
|
1542
|
|
|
if ($node->isSameNode($dataNode)) |
|
1543
|
|
|
return $dataNode; |
|
1544
|
|
|
} |
|
1545
|
|
|
// if doesn't, add it |
|
1546
|
|
|
PhpQuery::$documents[$documentID]->dataNodes[] = $node; |
|
1547
|
|
|
return $node; |
|
1548
|
|
|
} |
|
1549
|
|
|
|
|
1550
|
|
|
protected static function dataRemoveNode($node, $documentID) |
|
1551
|
|
|
{ |
|
1552
|
|
|
// search are return if alredy exists |
|
1553
|
|
|
foreach (PhpQuery::$documents[$documentID]->dataNodes as $k => $dataNode) { |
|
1554
|
|
|
if ($node->isSameNode($dataNode)) { |
|
1555
|
|
|
unset(self::$documents[$documentID]->dataNodes[$k]); |
|
1556
|
|
|
unset(self::$documents[$documentID]->data[$dataNode->dataID]); |
|
1557
|
|
|
} |
|
1558
|
|
|
} |
|
1559
|
|
|
} |
|
1560
|
|
|
|
|
1561
|
|
|
public static function data($node, $name, $data, $documentID = null) |
|
1562
|
|
|
{ |
|
1563
|
|
|
if (!$documentID) |
|
1564
|
|
|
// TODO check if this works |
|
1565
|
|
|
$documentID = self::getDocumentID($node); |
|
1566
|
|
|
$document = PhpQuery::$documents[$documentID]; |
|
1567
|
|
|
$node = self::dataSetupNode($node, $documentID); |
|
1568
|
|
|
if (!isset($node->dataID)) |
|
1569
|
|
|
$node->dataID = ++PhpQuery::$documents[$documentID]->uuid; |
|
1570
|
|
|
$id = $node->dataID; |
|
1571
|
|
|
if (!isset($document->data[$id])) |
|
1572
|
|
|
$document->data[$id] = array(); |
|
1573
|
|
|
if (!is_null($data)) |
|
1574
|
|
|
$document->data[$id][$name] = $data; |
|
1575
|
|
|
if ($name) { |
|
1576
|
|
|
if (isset($document->data[$id][$name])) |
|
1577
|
|
|
return $document->data[$id][$name]; |
|
1578
|
|
|
} else |
|
1579
|
|
|
return $id; |
|
1580
|
|
|
} |
|
1581
|
|
|
|
|
1582
|
|
|
public static function removeData($node, $name, $documentID) |
|
1583
|
|
|
{ |
|
1584
|
|
|
if (!$documentID) |
|
1585
|
|
|
// TODO check if this works |
|
1586
|
|
|
$documentID = self::getDocumentID($node); |
|
1587
|
|
|
$document = PhpQuery::$documents[$documentID]; |
|
1588
|
|
|
$node = self::dataSetupNode($node, $documentID); |
|
1589
|
|
|
$id = $node->dataID; |
|
1590
|
|
|
if ($name) { |
|
1591
|
|
|
if (isset($document->data[$id][$name])) |
|
1592
|
|
|
unset($document->data[$id][$name]); |
|
1593
|
|
|
$name = null; |
|
1594
|
|
|
foreach ($document->data[$id] as $name) |
|
1595
|
|
|
break; |
|
1596
|
|
|
if (!$name) |
|
1597
|
|
|
self::removeData($node, $name, $documentID); |
|
1598
|
|
|
} else { |
|
1599
|
|
|
self::dataRemoveNode($node, $documentID); |
|
1600
|
|
|
} |
|
1601
|
|
|
} |
|
1602
|
|
|
} |
|
1603
|
|
|
|
|
1604
|
|
|
/** |
|
1605
|
|
|
* Plugins static namespace class. |
|
1606
|
|
|
* |
|
1607
|
|
|
* @author Tobiasz Cudnik <tobiasz.cudnik/gmail.com> |
|
1608
|
|
|
* @package PhpQuery |
|
1609
|
|
|
* @todo move plugin methods here (as statics) |
|
1610
|
|
|
*/ |
|
1611
|
|
|
class PhpQueryPlugins |
|
|
|
|
|
|
1612
|
|
|
{ |
|
1613
|
|
|
public function __call($method, $args) |
|
1614
|
|
|
{ |
|
1615
|
|
|
if (isset(PhpQuery::$extendStaticMethods[$method])) { |
|
1616
|
|
|
$return = call_user_func_array(PhpQuery::$extendStaticMethods[$method], $args); |
|
|
|
|
|
|
1617
|
|
|
} else if (isset(PhpQuery::$pluginsStaticMethods[$method])) { |
|
1618
|
|
|
$class = PhpQuery::$pluginsStaticMethods[$method]; |
|
1619
|
|
|
$realClass = "\PhpQuery\Plugin\Util$class"; |
|
1620
|
|
|
$return = call_user_func_array( |
|
1621
|
|
|
array( |
|
1622
|
|
|
$realClass, |
|
1623
|
|
|
$method |
|
1624
|
|
|
), |
|
1625
|
|
|
$args |
|
1626
|
|
|
); |
|
1627
|
|
|
return isset($return) ? $return : $this; |
|
1628
|
|
|
} else |
|
1629
|
|
|
throw new \Exception("Method '{$method}' doesnt exist"); |
|
1630
|
|
|
} |
|
1631
|
|
|
} |
|
1632
|
|
|
|
|
1633
|
|
|
PhpQuery::$plugins = new PhpQueryPlugins(); |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.