Просмотр файла news/libraries/web.php

Размер файла: 24.47Kb
  1. <?php
  2.  
  3. /*
  4. Copyright (c) 2009-2014 F3::Factory/Bong Cosca, All rights reserved.
  5.  
  6. This file is part of the Fat-Free Framework (http://fatfree.sf.net).
  7.  
  8. THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
  9. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  10. IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  11. PURPOSE.
  12.  
  13. Please see the license.txt file for more information.
  14. */
  15.  
  16. //! Wrapper for various HTTP utilities
  17. class Web extends Prefab {
  18.  
  19. //@{ Error messages
  20. const
  21. E_Request='No suitable HTTP request engine found';
  22. //@}
  23.  
  24. protected
  25. //! HTTP request engine
  26. $wrapper;
  27.  
  28. /**
  29. * Detect MIME type using file extension
  30. * @return string
  31. * @param $file string
  32. **/
  33. function mime($file) {
  34. if (preg_match('/\w+$/',$file,$ext)) {
  35. $map=array(
  36. 'au'=>'audio/basic',
  37. 'avi'=>'video/avi',
  38. 'bmp'=>'image/bmp',
  39. 'bz2'=>'application/x-bzip2',
  40. 'css'=>'text/css',
  41. 'dtd'=>'application/xml-dtd',
  42. 'doc'=>'application/msword',
  43. 'gif'=>'image/gif',
  44. 'gz'=>'application/x-gzip',
  45. 'hqx'=>'application/mac-binhex40',
  46. 'html?'=>'text/html',
  47. 'jar'=>'application/java-archive',
  48. 'jpe?g'=>'image/jpeg',
  49. 'js'=>'application/x-javascript',
  50. 'midi'=>'audio/x-midi',
  51. 'mp3'=>'audio/mpeg',
  52. 'mpe?g'=>'video/mpeg',
  53. 'ogg'=>'audio/vorbis',
  54. 'pdf'=>'application/pdf',
  55. 'png'=>'image/png',
  56. 'ppt'=>'application/vnd.ms-powerpoint',
  57. 'ps'=>'application/postscript',
  58. 'qt'=>'video/quicktime',
  59. 'ram?'=>'audio/x-pn-realaudio',
  60. 'rdf'=>'application/rdf',
  61. 'rtf'=>'application/rtf',
  62. 'sgml?'=>'text/sgml',
  63. 'sit'=>'application/x-stuffit',
  64. 'svg'=>'image/svg+xml',
  65. 'swf'=>'application/x-shockwave-flash',
  66. 'tgz'=>'application/x-tar',
  67. 'tiff'=>'image/tiff',
  68. 'txt'=>'text/plain',
  69. 'wav'=>'audio/wav',
  70. 'xls'=>'application/vnd.ms-excel',
  71. 'xml'=>'application/xml',
  72. 'zip'=>'application/x-zip-compressed'
  73. );
  74. foreach ($map as $key=>$val)
  75. if (preg_match('/'.$key.'/',strtolower($ext[0])))
  76. return $val;
  77. }
  78. return 'application/octet-stream';
  79. }
  80.  
  81. /**
  82. * Return the MIME types stated in the HTTP Accept header as an array;
  83. * If a list of MIME types is specified, return the best match; or
  84. * FALSE if none found
  85. * @return array|string|FALSE
  86. * @param $list string|array
  87. **/
  88. function acceptable($list=NULL) {
  89. $accept=array();
  90. foreach (explode(',',str_replace(' ','',$_SERVER['HTTP_ACCEPT']))
  91. as $mime)
  92. if (preg_match('/(.+?)(?:;q=([\d\.]+)|$)/',$mime,$parts))
  93. $accept[$parts[1]]=isset($parts[2])?$parts[2]:1;
  94. if (!$accept)
  95. $accept['*/*']=1;
  96. else {
  97. krsort($accept);
  98. arsort($accept);
  99. }
  100. if ($list) {
  101. if (is_string($list))
  102. $list=explode(',',$list);
  103. foreach ($accept as $mime=>$q)
  104. if ($q && $out=preg_grep('/'.
  105. str_replace('\*','.*',preg_quote($mime,'/')).'/',$list))
  106. return current($out);
  107. return FALSE;
  108. }
  109. return $accept;
  110. }
  111.  
  112. /**
  113. * Transmit file to HTTP client; Return file size if successful,
  114. * FALSE otherwise
  115. * @return int|FALSE
  116. * @param $file string
  117. * @param $mime string
  118. * @param $kbps int
  119. * @param $force bool
  120. **/
  121. function send($file,$mime=NULL,$kbps=0,$force=TRUE) {
  122. if (!is_file($file))
  123. return FALSE;
  124. if (PHP_SAPI!='cli') {
  125. header('Content-Type: '.($mime?:$this->mime($file)));
  126. if ($force)
  127. header('Content-Disposition: attachment; '.
  128. 'filename='.basename($file));
  129. header('Accept-Ranges: bytes');
  130. header('Content-Length: '.$size=filesize($file));
  131. header('X-Powered-By: '.Base::instance()->get('PACKAGE'));
  132. }
  133. $ctr=0;
  134. $handle=fopen($file,'rb');
  135. $start=microtime(TRUE);
  136. while (!feof($handle) &&
  137. ($info=stream_get_meta_data($handle)) &&
  138. !$info['timed_out'] && !connection_aborted()) {
  139. if ($kbps) {
  140. // Throttle output
  141. $ctr++;
  142. if ($ctr/$kbps>$elapsed=microtime(TRUE)-$start)
  143. usleep(1e6*($ctr/$kbps-$elapsed));
  144. }
  145. // Send 1KiB and reset timer
  146. echo fread($handle,1024);
  147. }
  148. fclose($handle);
  149. return $size;
  150. }
  151.  
  152. /**
  153. * Receive file(s) from HTTP client
  154. * @return array|bool
  155. * @param $func callback
  156. * @param $overwrite bool
  157. * @param $slug callback|bool
  158. **/
  159. function receive($func=NULL,$overwrite=FALSE,$slug=TRUE) {
  160. $fw=Base::instance();
  161. $dir=$fw->get('UPLOADS');
  162. if (!is_dir($dir))
  163. mkdir($dir,Base::MODE,TRUE);
  164. if ($fw->get('VERB')=='PUT') {
  165. $tmp=$fw->get('TEMP').
  166. $fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
  167. $fw->hash(uniqid());
  168. if (!$fw->get('RAW'))
  169. $fw->write($tmp,$fw->get('BODY'));
  170. else {
  171. $src=@fopen('php://input','r');
  172. $dst=@fopen($tmp,'w');
  173. if (!$src || !$dst)
  174. return FALSE;
  175. while (!feof($src) &&
  176. ($info=stream_get_meta_data($src)) &&
  177. !$info['timed_out'] && $str=fgets($src,4096))
  178. fputs($dst,$str,strlen($str));
  179. fclose($dst);
  180. fclose($src);
  181. }
  182. $base=basename($fw->get('URI'));
  183. $file=array(
  184. 'name'=>$dir.
  185. ($slug && preg_match('/(.+?)(\.\w+)?$/',$base,$parts)?
  186. (is_callable($slug)?
  187. $slug($base):
  188. ($this->slug($parts[1]).
  189. (isset($parts[2])?$parts[2]:''))):
  190. $base),
  191. 'tmp_name'=>$tmp,
  192. 'type'=>$this->mime($base),
  193. 'size'=>filesize($tmp)
  194. );
  195. return (!file_exists($file['name']) || $overwrite) &&
  196. (!$func || $fw->call($func,array($file))!==FALSE) &&
  197. rename($tmp,$file['name']);
  198. }
  199. $out=array();
  200. foreach ($_FILES as $item) {
  201. if (is_array($item['name'])) {
  202. // Transpose array
  203. $tmp=array();
  204. foreach ($item as $keyx=>$cols)
  205. foreach ($cols as $keyy=>$valy)
  206. $tmp[$keyy][$keyx]=$valy;
  207. $item=$tmp;
  208. }
  209. else
  210. $item=array($item);
  211. foreach ($item as $file) {
  212. if (empty($file['name']))
  213. continue;
  214. $base=basename($file['name']);
  215. $file['name']=$dir.
  216. ($slug && preg_match('/(.+?)(\.\w+)?$/',$base,$parts)?
  217. (is_callable($slug)?
  218. $slug($base):
  219. ($this->slug($parts[1]).
  220. (isset($parts[2])?$parts[2]:''))):
  221. $base);
  222. $out[$file['name']]=!$file['error'] &&
  223. is_uploaded_file($file['tmp_name']) &&
  224. (!file_exists($file['name']) || $overwrite) &&
  225. (!$func || $fw->call($func,array($file))!==FALSE) &&
  226. move_uploaded_file($file['tmp_name'],$file['name']);
  227. }
  228. }
  229. return $out;
  230. }
  231.  
  232. /**
  233. * Return upload progress in bytes, FALSE on failure
  234. * @return int|FALSE
  235. * @param $id string
  236. **/
  237. function progress($id) {
  238. // ID returned by session.upload_progress.name
  239. return ini_get('session.upload_progress.enabled') &&
  240. isset($_SESSION[$id]['bytes_processed'])?
  241. $_SESSION[$id]['bytes_processed']:FALSE;
  242. }
  243.  
  244. /**
  245. * HTTP request via cURL
  246. * @return array
  247. * @param $url string
  248. * @param $options array
  249. **/
  250. protected function _curl($url,$options) {
  251. $curl=curl_init($url);
  252. curl_setopt($curl,CURLOPT_FOLLOWLOCATION,
  253. $options['follow_location']);
  254. curl_setopt($curl,CURLOPT_MAXREDIRS,
  255. $options['max_redirects']);
  256. curl_setopt($curl,CURLOPT_CUSTOMREQUEST,$options['method']);
  257. if (isset($options['header']))
  258. curl_setopt($curl,CURLOPT_HTTPHEADER,$options['header']);
  259. if (isset($options['user_agent']))
  260. curl_setopt($curl,CURLOPT_USERAGENT,$options['user_agent']);
  261. if (isset($options['content']))
  262. curl_setopt($curl,CURLOPT_POSTFIELDS,$options['content']);
  263. curl_setopt($curl,CURLOPT_ENCODING,'gzip,deflate');
  264. $timeout=isset($options['timeout'])?
  265. $options['timeout']:
  266. ini_get('default_socket_timeout');
  267. curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,$timeout);
  268. curl_setopt($curl,CURLOPT_TIMEOUT,$timeout);
  269. $headers=array();
  270. curl_setopt($curl,CURLOPT_HEADERFUNCTION,
  271. // Callback for response headers
  272. function($curl,$line) use(&$headers) {
  273. if ($trim=trim($line))
  274. $headers[]=$trim;
  275. return strlen($line);
  276. }
  277. );
  278. curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);
  279. ob_start();
  280. curl_exec($curl);
  281. curl_close($curl);
  282. $body=ob_get_clean();
  283. return array(
  284. 'body'=>$body,
  285. 'headers'=>$headers,
  286. 'engine'=>'cURL',
  287. 'cached'=>FALSE
  288. );
  289. }
  290.  
  291. /**
  292. * HTTP request via PHP stream wrapper
  293. * @return array
  294. * @param $url string
  295. * @param $options array
  296. **/
  297. protected function _stream($url,$options) {
  298. $eol="\r\n";
  299. $options['header']=implode($eol,$options['header']);
  300. $body=@file_get_contents($url,FALSE,
  301. stream_context_create(array('http'=>$options)));
  302. $headers=isset($http_response_header)?
  303. $http_response_header:array();
  304. $match=NULL;
  305. foreach ($headers as $header)
  306. if (preg_match('/Content-Encoding: (.+)/',$header,$match))
  307. break;
  308. if ($match)
  309. switch ($match[1]) {
  310. case 'gzip':
  311. $body=gzdecode($body);
  312. break;
  313. case 'deflate':
  314. $body=gzuncompress($body);
  315. break;
  316. }
  317. return array(
  318. 'body'=>$body,
  319. 'headers'=>$headers,
  320. 'engine'=>'stream',
  321. 'cached'=>FALSE
  322. );
  323. }
  324.  
  325. /**
  326. * HTTP request via low-level TCP/IP socket
  327. * @return array
  328. * @param $url string
  329. * @param $options array
  330. **/
  331. protected function _socket($url,$options) {
  332. $eol="\r\n";
  333. $headers=array();
  334. $body='';
  335. $parts=parse_url($url);
  336. $empty=empty($parts['port']);
  337. if ($parts['scheme']=='https') {
  338. $parts['host']='ssl://'.$parts['host'];
  339. if ($empty)
  340. $parts['port']=443;
  341. }
  342. elseif ($empty)
  343. $parts['port']=80;
  344. if (empty($parts['path']))
  345. $parts['path']='/';
  346. if (empty($parts['query']))
  347. $parts['query']='';
  348. $socket=@fsockopen($parts['host'],$parts['port']);
  349. if (!$socket)
  350. return FALSE;
  351. stream_set_blocking($socket,TRUE);
  352. fputs($socket,$options['method'].' '.$parts['path'].
  353. ($parts['query']?('?'.$parts['query']):'').' HTTP/1.0'.$eol
  354. );
  355. fputs($socket,implode($eol,$options['header']).$eol.$eol);
  356. if (isset($options['content']))
  357. fputs($socket,$options['content'].$eol);
  358. // Get response
  359. $content='';
  360. while (!feof($socket) &&
  361. ($info=stream_get_meta_data($socket)) &&
  362. !$info['timed_out'] && $str=fgets($socket,4096))
  363. $content.=$str;
  364. fclose($socket);
  365. $html=explode($eol.$eol,$content,2);
  366. $body=isset($html[1])?$html[1]:'';
  367. $headers=array_merge($headers,$current=explode($eol,$html[0]));
  368. $match=NULL;
  369. foreach ($current as $header)
  370. if (preg_match('/Content-Encoding: (.+)/',$header,$match))
  371. break;
  372. if ($match)
  373. switch ($match[1]) {
  374. case 'gzip':
  375. $body=gzdecode($body);
  376. break;
  377. case 'deflate':
  378. $body=gzuncompress($body);
  379. break;
  380. }
  381. if ($options['follow_location'] &&
  382. preg_match('/Location: (.+?)'.preg_quote($eol).'/',
  383. $html[0],$loc)) {
  384. $options['max_redirects']--;
  385. return $this->request($loc[1],$options);
  386. }
  387. return array(
  388. 'body'=>$body,
  389. 'headers'=>$headers,
  390. 'engine'=>'socket',
  391. 'cached'=>FALSE
  392. );
  393. }
  394.  
  395. /**
  396. * Specify the HTTP request engine to use; If not available,
  397. * fall back to an applicable substitute
  398. * @return string
  399. * @param $arg string
  400. **/
  401. function engine($arg='curl') {
  402. $arg=strtolower($arg);
  403. $flags=array(
  404. 'curl'=>extension_loaded('curl'),
  405. 'stream'=>ini_get('allow_url_fopen'),
  406. 'socket'=>function_exists('fsockopen')
  407. );
  408. if ($flags[$arg])
  409. return $this->wrapper=$arg;
  410. foreach ($flags as $key=>$val)
  411. if ($val)
  412. return $this->wrapper=$key;
  413. user_error(E_Request);
  414. }
  415.  
  416. /**
  417. * Replace old headers with new elements
  418. * @return NULL
  419. * @param $old array
  420. * @param $new string|array
  421. **/
  422. function subst(array &$old,$new) {
  423. if (is_string($new))
  424. $new=array($new);
  425. foreach ($new as $hdr) {
  426. $old=preg_grep('/'.preg_quote(strstr($hdr,':',TRUE),'/').':.+/',
  427. $old,PREG_GREP_INVERT);
  428. array_push($old,$hdr);
  429. }
  430. }
  431.  
  432. /**
  433. * Submit HTTP request; Use HTTP context options (described in
  434. * http://www.php.net/manual/en/context.http.php) if specified;
  435. * Cache the page as instructed by remote server
  436. * @return array|FALSE
  437. * @param $url string
  438. * @param $options array
  439. **/
  440. function request($url,array $options=NULL) {
  441. $fw=Base::instance();
  442. $parts=parse_url($url);
  443. if (empty($parts['scheme'])) {
  444. // Local URL
  445. $url=$fw->get('SCHEME').'://'.
  446. $fw->get('HOST').
  447. ($url[0]!='/'?($fw->get('BASE').'/'):'').$url;
  448. $parts=parse_url($url);
  449. }
  450. elseif (!preg_match('/https?/',$parts['scheme']))
  451. return FALSE;
  452. if (!is_array($options))
  453. $options=array();
  454. if (empty($options['header']))
  455. $options['header']=array();
  456. elseif (is_string($options['header']))
  457. $options['header']=array($options['header']);
  458. if (!$this->wrapper)
  459. $this->engine();
  460. if ($this->wrapper!='stream') {
  461. // PHP streams can't cope with redirects when Host header is set
  462. foreach ($options['header'] as &$header)
  463. if (preg_match('/^Host:/',$header)) {
  464. $header='Host: '.$parts['host'];
  465. unset($header);
  466. break;
  467. }
  468. $this->subst($options['header'],'Host: '.$parts['host']);
  469. }
  470. $this->subst($options['header'],
  471. array(
  472. 'Accept-Encoding: gzip,deflate',
  473. 'User-Agent: Mozilla/5.0 (compatible; '.php_uname('s').')',
  474. 'Connection: close'
  475. )
  476. );
  477. if (isset($options['content'])) {
  478. if ($options['method']=='POST')
  479. $this->subst($options['header'],
  480. 'Content-Type: application/x-www-form-urlencoded');
  481. $this->subst($options['header'],
  482. 'Content-Length: '.strlen($options['content']));
  483. }
  484. if (isset($parts['user'],$parts['pass']))
  485. $this->subst($options['header'],
  486. 'Authorization: Basic '.
  487. base64_encode($parts['user'].':'.$parts['pass'])
  488. );
  489. $options+=array(
  490. 'method'=>'GET',
  491. 'header'=>$options['header'],
  492. 'follow_location'=>TRUE,
  493. 'max_redirects'=>20,
  494. 'ignore_errors'=>FALSE
  495. );
  496. $eol="\r\n";
  497. if ($fw->get('CACHE') &&
  498. preg_match('/GET|HEAD/',$options['method'])) {
  499. $cache=Cache::instance();
  500. if ($cache->exists(
  501. $hash=$fw->hash($options['method'].' '.$url).'.url',$data)) {
  502. if (preg_match('/Last-Modified: (.+?)'.preg_quote($eol).'/',
  503. implode($eol,$data['headers']),$mod))
  504. $this->subst($options['header'],
  505. 'If-Modified-Since: '.$mod[1]);
  506. }
  507. }
  508. $result=$this->{'_'.$this->wrapper}($url,$options);
  509. if ($result && isset($cache)) {
  510. if (preg_match('/HTTP\/1\.\d 304/',
  511. implode($eol,$result['headers']))) {
  512. $result=$cache->get($hash);
  513. $result['cached']=TRUE;
  514. }
  515. elseif (preg_match('/Cache-Control: max-age=(.+?)'.
  516. preg_quote($eol).'/',implode($eol,$result['headers']),$exp))
  517. $cache->set($hash,$result,$exp[1]);
  518. }
  519. return $result;
  520. }
  521.  
  522. /**
  523. * Strip Javascript/CSS files of extraneous whitespaces and comments;
  524. * Return combined output as a minified string
  525. * @return string
  526. * @param $files string|array
  527. * @param $mime string
  528. * @param $header bool
  529. * @param $path string
  530. **/
  531. function minify($files,$mime=NULL,$header=TRUE,$path='') {
  532. $fw=Base::instance();
  533. if (is_string($files))
  534. $files=$fw->split($files);
  535. if (!$mime)
  536. $mime=$this->mime($files[0]);
  537. preg_match('/\w+$/',$files[0],$ext);
  538. $cache=Cache::instance();
  539. $dst='';
  540. foreach ($fw->split($path?:$fw->get('UI').';./') as $dir)
  541. foreach ($files as $file)
  542. if (is_file($save=$fw->fixslashes($dir.$file))) {
  543. if ($fw->get('CACHE') &&
  544. ($cached=$cache->exists(
  545. $hash=$fw->hash($save).'.'.$ext[0],$data)) &&
  546. $cached[0]>filemtime($save))
  547. $dst.=$data;
  548. else {
  549. $data='';
  550. $src=$fw->read($save);
  551. for ($ptr=0,$len=strlen($src);$ptr<$len;) {
  552. if (preg_match('/^@import\h+url'.
  553. '\(\h*([\'"])(.+?)\1\h*\)[^;]*;/',
  554. substr($src,$ptr),$parts)) {
  555. $path=dirname($file);
  556. $data.=$this->minify(
  557. ($path?($path.'/'):'').$parts[2],
  558. $mime,$header
  559. );
  560. $ptr+=strlen($parts[0]);
  561. continue;
  562. }
  563. if ($src[$ptr]=='/') {
  564. if ($src[$ptr+1]=='*') {
  565. // Multiline comment
  566. $str=strstr(
  567. substr($src,$ptr+2),'*/',TRUE);
  568. $ptr+=strlen($str)+4;
  569. }
  570. elseif ($src[$ptr+1]=='/') {
  571. // Single-line comment
  572. $str=strstr(
  573. substr($src,$ptr+2),"\n",TRUE);
  574. $ptr+=strlen($str)+2;
  575. }
  576. else {
  577. // Presume it's a regex pattern
  578. $regex=TRUE;
  579. // Backtrack and validate
  580. for ($ofs=$ptr;$ofs;$ofs--) {
  581. // Pattern should be preceded by
  582. // open parenthesis, colon,
  583. // object property or operator
  584. if (preg_match(
  585. '/(return|[(:=!+\-*&|])$/',
  586. substr($src,0,$ofs))) {
  587. $data.='/';
  588. $ptr++;
  589. while ($ptr<$len) {
  590. $data.=$src[$ptr];
  591. $ptr++;
  592. if ($src[$ptr-1]=='\\') {
  593. $data.=$src[$ptr];
  594. $ptr++;
  595. }
  596. elseif ($src[$ptr-1]=='/')
  597. break;
  598. }
  599. break;
  600. }
  601. elseif (!ctype_space($src[$ofs-1])) {
  602. // Not a regex pattern
  603. $regex=FALSE;
  604. break;
  605. }
  606. }
  607. if (!$regex) {
  608. // Division operator
  609. $data.=$src[$ptr];
  610. $ptr++;
  611. }
  612. }
  613. continue;
  614. }
  615. if (in_array($src[$ptr],array('\'','"'))) {
  616. $match=$src[$ptr];
  617. $data.=$match;
  618. $ptr++;
  619. // String literal
  620. while ($ptr<$len) {
  621. $data.=$src[$ptr];
  622. $ptr++;
  623. if ($src[$ptr-1]=='\\') {
  624. $data.=$src[$ptr];
  625. $ptr++;
  626. }
  627. elseif ($src[$ptr-1]==$match)
  628. break;
  629. }
  630. continue;
  631. }
  632. if (ctype_space($src[$ptr])) {
  633. if ($ptr+1<strlen($src) &&
  634. preg_match('/[\w'.($ext[0]=='css'?
  635. '#\.+\-*()\[\]':'\$').']{2}|'.
  636. '[+\-]{2}/',
  637. substr($data,-1).$src[$ptr+1]))
  638. $data.=' ';
  639. $ptr++;
  640. continue;
  641. }
  642. $data.=$src[$ptr];
  643. $ptr++;
  644. }
  645. if ($fw->get('CACHE'))
  646. $cache->set($hash,$data);
  647. $dst.=$data;
  648. }
  649. }
  650. if (PHP_SAPI!='cli' && $header)
  651. header('Content-Type: '.$mime.'; charset='.$fw->get('ENCODING'));
  652. return $dst;
  653. }
  654.  
  655. /**
  656. * Retrieve RSS feed and return as an array
  657. * @return array|FALSE
  658. * @param $url string
  659. * @param $max int
  660. * @param $tags string
  661. **/
  662. function rss($url,$max=10,$tags=NULL) {
  663. if (!$data=$this->request($url))
  664. return FALSE;
  665. // Suppress errors caused by invalid XML structures
  666. libxml_use_internal_errors(TRUE);
  667. $xml=simplexml_load_string($data['body'],
  668. NULL,LIBXML_NOBLANKS|LIBXML_NOERROR);
  669. if (!is_object($xml))
  670. return FALSE;
  671. $out=array();
  672. if (isset($xml->channel)) {
  673. $out['source']=(string)$xml->channel->title;
  674. $max=min($max,count($xml->channel->item));
  675. for ($i=0;$i<$max;$i++) {
  676. $item=$xml->channel->item[$i];
  677. $list=array(''=>NULL)+$item->getnamespaces(TRUE);
  678. $fields=array();
  679. foreach ($list as $ns=>$uri)
  680. foreach ($item->children($uri) as $key=>$val)
  681. $fields[$ns.($ns?':':'').$key]=(string)$val;
  682. $out['feed'][]=$fields;
  683. }
  684. }
  685. else
  686. return FALSE;
  687. Base::instance()->scrub($out,$tags);
  688. return $out;
  689. }
  690.  
  691. /**
  692. * Retrieve information from whois server
  693. * @return string|FALSE
  694. * @param $addr string
  695. * @param $server string
  696. **/
  697. function whois($addr,$server='whois.internic.net') {
  698. $socket=@fsockopen($server,43,$errno,$errstr);
  699. if (!$socket)
  700. // Can't establish connection
  701. return FALSE;
  702. // Set connection timeout parameters
  703. stream_set_blocking($socket,TRUE);
  704. stream_set_timeout($socket,ini_get('default_socket_timeout'));
  705. // Send request
  706. fputs($socket,$addr."\r\n");
  707. $info=stream_get_meta_data($socket);
  708. // Get response
  709. $response='';
  710. while (!feof($socket) && !$info['timed_out']) {
  711. $response.=fgets($socket,4096); // MDFK97
  712. $info=stream_get_meta_data($socket);
  713. }
  714. fclose($socket);
  715. return $info['timed_out']?FALSE:trim($response);
  716. }
  717.  
  718. /**
  719. * Return a URL/filesystem-friendly version of string
  720. * @return string
  721. * @param $text string
  722. **/
  723. function slug($text) {
  724. return trim(strtolower(preg_replace('/([^\pL\pN])+/u','-',
  725. trim(strtr(str_replace('\'','',$text),
  726. array(
  727. 'Ǎ'=>'A','А'=>'A','Ā'=>'A','Ă'=>'A','Ą'=>'A','Å'=>'A',
  728. 'Ǻ'=>'A','Ä'=>'Ae','Á'=>'A','À'=>'A','Ã'=>'A','Â'=>'A',
  729. 'Æ'=>'AE','Ǽ'=>'AE','Б'=>'B','Ç'=>'C','Ć'=>'C','Ĉ'=>'C',
  730. 'Č'=>'C','Ċ'=>'C','Ц'=>'C','Ч'=>'Ch','Ð'=>'Dj','Đ'=>'Dj',
  731. 'Ď'=>'Dj','Д'=>'Dj','É'=>'E','Ę'=>'E','Ё'=>'E','Ė'=>'E',
  732. 'Ê'=>'E','Ě'=>'E','Ē'=>'E','È'=>'E','Е'=>'E','Э'=>'E',
  733. 'Ë'=>'E','Ĕ'=>'E','Ф'=>'F','Г'=>'G','Ģ'=>'G','Ġ'=>'G',
  734. 'Ĝ'=>'G','Ğ'=>'G','Х'=>'H','Ĥ'=>'H','Ħ'=>'H','Ï'=>'I',
  735. 'Ĭ'=>'I','İ'=>'I','Į'=>'I','Ī'=>'I','Í'=>'I','Ì'=>'I',
  736. 'И'=>'I','Ǐ'=>'I','Ĩ'=>'I','Î'=>'I','IJ'=>'IJ','Ĵ'=>'J',
  737. 'Й'=>'J','Я'=>'Ja','Ю'=>'Ju','К'=>'K','Ķ'=>'K','Ĺ'=>'L',
  738. 'Л'=>'L','Ł'=>'L','Ŀ'=>'L','Ļ'=>'L','Ľ'=>'L','М'=>'M',
  739. 'Н'=>'N','Ń'=>'N','Ñ'=>'N','Ņ'=>'N','Ň'=>'N','Ō'=>'O',
  740. 'О'=>'O','Ǿ'=>'O','Ǒ'=>'O','Ơ'=>'O','Ŏ'=>'O','Ő'=>'O',
  741. 'Ø'=>'O','Ö'=>'Oe','Õ'=>'O','Ó'=>'O','Ò'=>'O','Ô'=>'O',
  742. 'Œ'=>'OE','П'=>'P','Ŗ'=>'R','Р'=>'R','Ř'=>'R','Ŕ'=>'R',
  743. 'Ŝ'=>'S','Ş'=>'S','Š'=>'S','Ș'=>'S','Ś'=>'S','С'=>'S',
  744. 'Ш'=>'Sh','Щ'=>'Shch','Ť'=>'T','Ŧ'=>'T','Ţ'=>'T','Ț'=>'T',
  745. 'Т'=>'T','Ů'=>'U','Ű'=>'U','Ŭ'=>'U','Ũ'=>'U','Ų'=>'U',
  746. 'Ū'=>'U','Ǜ'=>'U','Ǚ'=>'U','Ù'=>'U','Ú'=>'U','Ü'=>'Ue',
  747. 'Ǘ'=>'U','Ǖ'=>'U','У'=>'U','Ư'=>'U','Ǔ'=>'U','Û'=>'U',
  748. 'В'=>'V','Ŵ'=>'W','Ы'=>'Y','Ŷ'=>'Y','Ý'=>'Y','Ÿ'=>'Y',
  749. 'Ź'=>'Z','З'=>'Z','Ż'=>'Z','Ž'=>'Z','Ж'=>'Zh','á'=>'a',
  750. 'ă'=>'a','â'=>'a','à'=>'a','ā'=>'a','ǻ'=>'a','å'=>'a',
  751. 'ä'=>'ae','ą'=>'a','ǎ'=>'a','ã'=>'a','а'=>'a','ª'=>'a',
  752. 'æ'=>'ae','ǽ'=>'ae','б'=>'b','č'=>'c','ç'=>'c','ц'=>'c',
  753. 'ċ'=>'c','ĉ'=>'c','ć'=>'c','ч'=>'ch','ð'=>'dj','ď'=>'dj',
  754. 'д'=>'dj','đ'=>'dj','э'=>'e','é'=>'e','ё'=>'e','ë'=>'e',
  755. 'ê'=>'e','е'=>'e','ĕ'=>'e','è'=>'e','ę'=>'e','ě'=>'e',
  756. 'ė'=>'e','ē'=>'e','ƒ'=>'f','ф'=>'f','ġ'=>'g','ĝ'=>'g',
  757. 'ğ'=>'g','г'=>'g','ģ'=>'g','х'=>'h','ĥ'=>'h','ħ'=>'h',
  758. 'ǐ'=>'i','ĭ'=>'i','и'=>'i','ī'=>'i','ĩ'=>'i','į'=>'i',
  759. 'ı'=>'i','ì'=>'i','î'=>'i','í'=>'i','ï'=>'i','ij'=>'ij',
  760. 'ĵ'=>'j','й'=>'j','я'=>'ja','ю'=>'ju','ķ'=>'k','к'=>'k',
  761. 'ľ'=>'l','ł'=>'l','ŀ'=>'l','ĺ'=>'l','ļ'=>'l','л'=>'l',
  762. 'м'=>'m','ņ'=>'n','ñ'=>'n','ń'=>'n','н'=>'n','ň'=>'n',
  763. 'ʼn'=>'n','ó'=>'o','ò'=>'o','ǒ'=>'o','ő'=>'o','о'=>'o',
  764. 'ō'=>'o','º'=>'o','ơ'=>'o','ŏ'=>'o','ô'=>'o','ö'=>'oe',
  765. 'õ'=>'o','ø'=>'o','ǿ'=>'o','œ'=>'oe','п'=>'p','р'=>'r',
  766. 'ř'=>'r','ŕ'=>'r','ŗ'=>'r','ſ'=>'s','ŝ'=>'s','ș'=>'s',
  767. 'š'=>'s','ś'=>'s','с'=>'s','ş'=>'s','ш'=>'sh','щ'=>'shch',
  768. 'ß'=>'ss','ţ'=>'t','т'=>'t','ŧ'=>'t','ť'=>'t','ț'=>'t',
  769. 'у'=>'u','ǘ'=>'u','ŭ'=>'u','û'=>'u','ú'=>'u','ų'=>'u',
  770. 'ù'=>'u','ű'=>'u','ů'=>'u','ư'=>'u','ū'=>'u','ǚ'=>'u',
  771. 'ǜ'=>'u','ǔ'=>'u','ǖ'=>'u','ũ'=>'u','ü'=>'ue','в'=>'v',
  772. 'ŵ'=>'w','ы'=>'y','ÿ'=>'y','ý'=>'y','ŷ'=>'y','ź'=>'z',
  773. 'ž'=>'z','з'=>'z','ż'=>'z','ж'=>'zh'
  774. )+Base::instance()->get('DIACRITICS'))))),'-');
  775. }
  776.  
  777. /**
  778. * Return chunk of text from standard Lorem Ipsum passage
  779. * @return string
  780. * @param $count int
  781. * @param $max int
  782. * @param $std bool
  783. **/
  784. function filler($count=1,$max=20,$std=TRUE) {
  785. $out='';
  786. if ($std)
  787. $out='Lorem ipsum dolor sit amet, consectetur adipisicing elit, '.
  788. 'sed do eiusmod tempor incididunt ut labore et dolore magna '.
  789. 'aliqua.';
  790. $rnd=explode(' ',
  791. 'a ab ad accusamus adipisci alias aliquam amet animi aperiam '.
  792. 'architecto asperiores aspernatur assumenda at atque aut beatae '.
  793. 'blanditiis cillum commodi consequatur corporis corrupti culpa '.
  794. 'cum cupiditate debitis delectus deleniti deserunt dicta '.
  795. 'dignissimos distinctio dolor ducimus duis ea eaque earum eius '.
  796. 'eligendi enim eos error esse est eum eveniet ex excepteur '.
  797. 'exercitationem expedita explicabo facere facilis fugiat harum '.
  798. 'hic id illum impedit in incidunt ipsa iste itaque iure iusto '.
  799. 'laborum laudantium libero magnam maiores maxime minim minus '.
  800. 'modi molestiae mollitia nam natus necessitatibus nemo neque '.
  801. 'nesciunt nihil nisi nobis non nostrum nulla numquam occaecati '.
  802. 'odio officia omnis optio pariatur perferendis perspiciatis '.
  803. 'placeat porro possimus praesentium proident quae quia quibus '.
  804. 'quo ratione recusandae reiciendis rem repellat reprehenderit '.
  805. 'repudiandae rerum saepe sapiente sequi similique sint soluta '.
  806. 'suscipit tempora tenetur totam ut ullam unde vel veniam vero '.
  807. 'vitae voluptas');
  808. for ($i=0,$add=$count-(int)$std;$i<$add;$i++) {
  809. shuffle($rnd);
  810. $words=array_slice($rnd,0,mt_rand(3,$max));
  811. $out.=' '.ucfirst(implode(' ',$words)).'.';
  812. }
  813. return $out;
  814. }
  815.  
  816. }
  817.  
  818. if (!function_exists('gzdecode')) {
  819.  
  820. /**
  821. * Decode gzip-compressed string
  822. * @param $str string
  823. **/
  824. function gzdecode($str) {
  825. $fw=Base::instance();
  826. if (!is_dir($tmp=$fw->get('TEMP')))
  827. mkdir($tmp,Base::MODE,TRUE);
  828. file_put_contents($file=$tmp.'/'.
  829. $fw->hash($fw->get('ROOT').$fw->get('BASE')).'.'.
  830. $fw->hash(uniqid(NULL,TRUE)).'.gz',$str,LOCK_EX);
  831. ob_start();
  832. readgzfile($file);
  833. $out=ob_get_clean();
  834. @unlink($file);
  835. return $out;
  836. }
  837.  
  838. }