source: extensions/pbase2piwigo/include/functions.inc.php @ 21631

Last change on this file since 21631 was 21291, checked in by mistic100, 12 years ago

safe_mode

File size: 11.5 KB
Line 
1<?php
2if (!defined('PBASE_PATH')) die('Hacking attempt!');
3
4/**
5 * get the content of web-page, with cache management
6 * @param: string url
7 * @return: string
8 */
9function get_file_cached($url)
10{
11  // html files are cached 10000 seconds
12  $cache_id_prefix = str_replace('http://www.pbase.com/', null, $url);
13  $cache_id_prefix = preg_replace('#([^a-z0-9-_]+)#i', null, $cache_id_prefix);
14  $cache_id = $cache_id_prefix.'-'.substr(time(), 0, -4);
15 
16  if (!file_exists(PBASE_FS_CACHE.$cache_id))
17  {
18    $files = glob(PBASE_FS_CACHE.$cache_id_prefix.'-*');
19    foreach ($files as $file) unlink($file);
20   
21    if (($result = download_remote_file($url, PBASE_FS_CACHE.$cache_id)) !== true)
22    {
23      return $result;
24    }
25  }
26 
27  $html = file_get_contents(PBASE_FS_CACHE.$cache_id);
28 
29  return utf8_encode($html);
30}
31
32/**
33 * helper to navigate throught the tree
34 * @param: &array tree
35 * @param: string path
36 * @return: reference to a branch of the tree
37 */
38function &get_current_cat(&$tree, $path)
39{
40  if (empty($path)) return $tree;
41 
42  $path = ltrim($path, '/');
43  $path = explode('/', $path);
44  $current = &$tree[ $path[0] ];
45  array_shift($path);
46 
47  foreach ($path as $folder)
48  {
49    $current = &$current['categories'][$folder];
50  }
51 
52  return $current;
53}
54
55/**
56 * check if give account (http://pbase.com/login/root) exists
57 * @param: string url
58 * @return: bool
59 */
60function check_account($url)
61{
62  $html = get_file_cached($url);
63  return !(bool)preg_match('#<h2>Unknown Account</h2>#i', $html);
64}
65
66/**
67 * parse a category page
68 * @param: string category url
69 * @param: bool parse only sub-categories
70 * @param: bool parse only one level
71 * @return: array category
72 */
73function parse_category($url, $path, $cats_only=false, $one_level=false)
74{
75  $url = str_replace('&page=all', null, $url);
76 
77  $current = array(
78    'url' => $url,
79    'path' => null,
80    'id' => null,
81    );
82   
83  // id
84  $temp = parse_url($url);
85  $temp = explode('/', $temp['path']);
86  $current['id'] = $temp[ count($temp)-1 ];
87  $current['path'] = $path.'/'.$current['id'];
88 
89  if ($one_level === 'stop')
90  {
91    return $current;
92  }
93   
94  $current = array_merge($current, array(
95    'title' => null,
96    'description' => null,
97    'pictures' => array(),
98    'categories' => array(),
99    'nb_pictures' => 0,
100    'nb_categories' => 0, 
101    ));
102   
103 
104  $url.= '&page=all'; // seriously... (should be ? not &)
105 
106 
107  $html = get_file_cached($url);
108  if ($html == 'file_error')
109  {
110    return $current;
111  }
112 
113  preg_match('#<body>(.*)</body>#is', $html, $matches);
114  $body = $matches[1];
115 
116  // content
117  // if (preg_match('#<CENTER>(.*)</CENTER>#is', $body, $matches) === 0) return 'null1';
118  if (preg_match_all('#<A HREF="([^">]*)" class="thumbnail">#i', $body, $matches) === 0) return $current;
119  $links = $matches[1];
120 
121  // title
122  if (preg_match('#<h2>(.*?)</h2>#i', $body, $matches))
123  {
124    $current['title'] = trim($matches[1]);
125  }
126  else
127  {
128    $current['title'] = $current['id'];
129  }
130 
131  // description
132  if (preg_match('#<!-- BEGIN user desc -->(.*?)<!-- END user desc -->#s', $body, $matches))
133  {
134    $current['description'] = trim($matches[1]);
135  }
136 
137  // sub-cats and pictures
138  foreach ($links as $link)
139  {
140    if (strpos($link, '/image/') !== false)
141    {
142      if (($image = parse_image($link, $cats_only)) !== null)
143      {
144        $current['pictures'][ $image['id'] ] = $image;
145      }
146      $current['nb_pictures']++;
147    }
148    else
149    {
150      $next_level = ($one_level === true) ? 'stop' : false;
151      if (($category = parse_category($link, $current['path'], $cats_only, $next_level)) !== null)
152      {
153        $current['categories'][ $category['id'] ] = $category;
154      }
155      $current['nb_categories']++;
156    }
157  }
158 
159  return $current;
160}
161
162/**
163 * parse a picture page
164 * @param: string picture url
165 * @param: bool return only url and id
166 * @return: array picture
167 */
168function parse_image($url, $light=false)
169{
170  $url = preg_replace('#/(small|medium|large|original)$#', null, $url);
171 
172  $current = array(
173    'url' => $url,
174    'id' => null,
175    );
176   
177  // id
178  $temp = parse_url($url);
179  $temp = explode('/', $temp['path']);
180  $current['id'] = $temp[ count($temp)-1 ];
181 
182  if ($light)
183  {
184    return $current;
185  }
186 
187  $current = array_merge($current, array(
188    'title' => null,
189    'path' => null,
190    'description' => null,
191    'date' => null,
192    'author' => null,
193    'keywords' => array(),
194    ));
195   
196  $url.= '/original';
197 
198 
199  $html = get_file_cached($url);
200  if ($html == 'file_error')
201  {
202    return $current;
203  }
204 
205  preg_match('#<body>(.*)</body>#is', $html, $matches);
206  $body = $matches[1];
207 
208  // path
209  if (preg_match('#<IMG ([^>]*)class="display" src="([^">]*)"#i', $body, $matches) ===0) return null;
210  $current['path'] = $matches[2];
211 
212  // title
213  preg_match('#<span class="title">(.*?)</span>#i', $body, $matches);
214  if (!empty($matches[1]))
215  {
216    $current['title'] = trim($matches[1]);
217    $current['title'] = get_filename_wo_extension($current['title']);
218  }
219  else
220  {
221    $current['title'] = $current['id'];
222  }
223 
224  // description
225  if (preg_match('#<p class="caption">(.*?)</p>#is', $body, $matches))
226  {
227    $current['description'] = trim($matches[1]);
228  }
229 
230  // date
231  if (preg_match('#<span class=date>(.*?)</span>#i', $body, $matches))
232  {
233    $current['date'] = trim($matches[1]);
234  }
235 
236  // author
237  if (preg_match('#<span class=artist>(.*?)</span>#i', $body, $matches))
238  {
239    $current['author'] = trim($matches[1]);
240  }
241 
242 
243  preg_match('#<head>(.*)</head>#is', $html, $matches);
244  $head = $matches[1];
245 
246  // keywords
247  if (preg_match('#<meta name="keywords" content="([^">]*)">#i', $head, $matches))
248  {
249    $words = explode(',', $matches[1]);
250    foreach ($words as $word)
251    {
252      if (!empty($word)) $current['keywords'][] = trim($word);
253    }
254  }
255 
256  return $current;
257}
258
259/**
260 * print categories tree (list or select)
261 * @param: array tree
262 * @param: int level
263 * @param: string tree type (list|select)
264 * @return: string
265 */
266function print_tree(&$tree, $level=0, $type='list')
267{
268  $out = '';
269 
270  if ($type == 'list')
271  {
272    $out.= '<ul>';
273    foreach ($tree as $item)
274    {
275      $out.= '<li>';
276      $out.= '<a href="'.$item['url'].'">'.$item['title'].'</a> ['.$item['nb_pictures'].']';
277      if (!empty($item['categories']))
278        $out.= print_tree($item['categories'], $level+1, 'list');
279      $out.= '</li>';
280    }
281    $out.= '</ul>';
282  }
283  else if ($type == 'select')
284  {
285    $i=0;
286    foreach ($tree as $item)
287    {
288      $out.= '<option value="'.$item['path'].'"';
289      if ($level==0 and $i==0) $out.= ' selected="selected"';
290      $out.= '>';
291     
292      $out.= str_repeat('&nbsp;', $level*4);
293      $out.= '- '.$item['title'].' ['.$item['nb_pictures'].']';
294     
295      $out.= '</option>';
296     
297      if (!empty($item['categories']))
298        $out.= print_tree($item['categories'], $level+1, 'select');
299       
300      $i++;
301    }
302  }
303 
304  return $out;
305}
306
307/**
308 * test if a download method is available
309 * @return: bool
310 */
311if (!function_exists('test_remote_download'))
312{
313  function test_remote_download()
314  {
315    return function_exists('curl_init') || ini_get('allow_url_fopen');
316  }
317}
318
319/**
320 * download a remote file
321 *  - needs cURL or allow_url_fopen
322 *  - take care of SSL urls
323 *
324 * @param: string source url
325 * @param: mixed destination file (if true, file content is returned)
326 */
327if (!function_exists('download_remote_file'))
328{
329  function download_remote_file($src, $dest)
330  {
331    if (empty($src))
332    {
333      return false;
334    }
335   
336    $return = ($dest === true) ? true : false;
337   
338    /* curl */
339    if (function_exists('curl_init'))
340    {
341      if (!$return)
342      {
343        $newf = fopen($dest, "wb");
344      }
345      $ch = curl_init();
346     
347      curl_setopt($ch, CURLOPT_URL, $src);
348      curl_setopt($ch, CURLOPT_HEADER, false);
349      curl_setopt($ch, CURLOPT_HTTPHEADER, array("Accept-language: en"));
350      curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)');
351      curl_setopt($ch, CURLOPT_TIMEOUT, 30);
352      if (!ini_get('safe_mode'))
353      {
354        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
355        curl_setopt($ch, CURLOPT_MAXREDIRS, 1);
356      }
357      if (strpos($src, 'https://') !== false)
358      {
359        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
360        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
361      }
362      if (!$return)
363      {
364        curl_setopt($ch, CURLOPT_FILE, $newf);
365      }
366      else
367      {
368        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
369      }
370     
371      $out = curl_exec($ch);
372      curl_close($ch);
373     
374      if ($out === false)
375      {
376        return 'file_error';
377      }
378      else if (!$return)
379      {
380        fclose($newf);
381        return true;
382      }
383      else
384      {
385        return $out;
386      }
387    }
388    /* file get content */
389    else if (ini_get('allow_url_fopen'))
390    {
391      if (strpos($src, 'https://') !== false and !extension_loaded('openssl'))
392      {
393        return false;
394      }
395     
396      $opts = array(
397        'http' => array(
398          'method' => "GET",
399          'user_agent' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)',
400          'header' => "Accept-language: en",
401        )
402      );
403
404      $context = stream_context_create($opts);
405     
406      if (($file = file_get_contents($src, false, $context)) === false)
407      {
408        return 'file_error';
409      }
410     
411      if (!$return)
412      {
413        file_put_contents($dest, $file);
414        return true;
415      }
416      else
417      {
418        return $file;
419      }
420    }
421   
422    return false;
423  }
424}
425
426/**
427 * count pictures and cats in the selected cat
428 * @param: &array tree
429 * @param: string $path
430 * @param: &int nb pictures
431 * @param: &int nb categories
432 * @param: bool recursive
433 * @return: void
434 */
435function count_pictures_cats(&$tree, $path, &$nb_pictures, &$nb_categories, $recursive=true)
436{
437  $current = &get_current_cat($tree, $path);
438  $nb_pictures+= $current['nb_pictures'];
439  $nb_categories++;
440 
441  if ( $recursive and !empty($current['categories']) )
442  {
443    foreach ($current['categories'] as $cat)
444    {
445      count_pictures_cats($tree, $cat['path'], $nb_pictures, $nb_categories, $recursive);
446    }
447  }
448}
449
450/**
451 * extract unique values of the specified key in a two dimensional array
452 * @param: array
453 * @param: mixed key name
454 * @return: array
455 */
456if (!function_exists('array_unique_deep'))
457{
458  function array_unique_deep(&$array, $key)
459  {
460    $values = array();
461    foreach ($array as $k1 => $row)
462    {
463      foreach ($row as $k2 => $v)
464      {
465        if ($k2 == $key)
466        {
467          $values[ $k1 ] = $v;
468          continue;
469        }
470      }
471    }
472    return array_unique($values);
473  }
474}
475
476/**
477 * search a string in array values
478 * // http://www.strangeplanet.fr/blog/dev/php-une-fonction-pour-rechercher-dans-un-tableau
479 * @param string needle
480 * @param array haystack
481 * @param bool return all instances
482 * @param bool search in PCRE mode
483 * @return key or array of keys
484 */
485if (!function_exists('array_pos'))
486{
487  function array_pos($needle, &$haystack, $match_all=false, $preg_mode=false)
488  {
489    if ($match_all) $matches = array();
490   
491    foreach ($haystack as $i => $row)
492    {
493      if (!is_array($row))
494      {
495        if (!$preg_mode)
496        {
497          if (strpos($row, $needle) !== false)
498          {
499            if (!$match_all) return $i;
500            else array_push($matches, $i);
501          }
502        }
503        else
504        {
505          if (preg_match($needle, $row) === 1)
506          {
507            if (!$match_all) return $i;
508            else array_push($matches, $i);
509          }
510        }
511      }
512    }
513   
514    if ( !$match_all or !count($matches) ) return false;
515    return $matches;
516  }
517}
518
519?>
Note: See TracBrowser for help on using the repository browser.