source: extensions/BatchDownloader/include/BatchDownloader.class.php @ 17177

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

rewrite all urls to be compatible with "question_mark_in_urls"

File size: 16.2 KB
Line 
1<?php
2defined('BATCH_DOWNLOAD_PATH') or die('Hacking attempt!');
3
4class BatchDownloader
5{
6  private $conf;
7  private $data;
8  private $images;
9 
10  /**
11   * __construct
12   * @param: mixed set id (##|'new')
13   * @param: array images
14   * @param: string set type ('album'|'tag'|'selection')
15   * @param: int set type id (for retrieving album infos for instance)
16   */
17  function __construct($set_id, $images=array(), $type=null, $type_id=null)
18  {
19    global $user, $conf;
20   
21    $this->conf = $conf['batch_download'];
22    $this->conf['archive_acomment'] = $conf['batch_download_comment'];
23    $this->data = array(
24      'id' => 0,
25      'user_id' => $user['id'],
26      'date_creation' => '0000-00-00 00:00:00',
27      'type' => null,
28      'type_id' => null,
29      'nb_zip' => 0,
30      'last_zip' => 0,
31      'nb_images' => 0,
32      'total_size' => 0,
33      'status' => 'new',
34      );
35    $this->images = array();
36   
37    // load specific set
38    if (preg_match('#^[0-9]+$#', $set_id))
39    {
40      $query = '
41SELECT
42    id,
43    user_id,
44    date_creation,
45    type,
46    type_id,
47    nb_zip,
48    last_zip,
49    nb_images,
50    total_size,
51    status
52  FROM '.BATCH_DOWNLOAD_TSETS.'
53  WHERE
54    id = '.$set_id.'
55    '.(!is_admin() ? 'AND user_id = '.$this->data['user_id'] : null).'
56;';
57      $result = pwg_query($query);
58     
59      if (pwg_db_num_rows($result))
60      {
61        $this->data = array_merge(
62          $this->data,
63          pwg_db_fetch_assoc($result)
64          );
65       
66        // make sur all pictures of the set exist
67        $query = '
68DELETE FROM '.BATCH_DOWNLOAD_TIMAGES.'
69  WHERE image_id NOT IN (
70    SELECT id FROM '.IMAGES_TABLE.'
71    )
72;';
73        pwg_query($query);
74     
75        $query = '
76SELECT
77    image_id,
78    zip
79  FROM '.BATCH_DOWNLOAD_TIMAGES.'
80  WHERE set_id = '.$this->data['id'].'
81;';
82        $this->images = simple_hash_from_query($query, 'image_id', 'zip');
83       
84        if ( $this->data['status'] != 'done' and count($this->images) != $this->data['nb_images'] )
85        {
86          $this->updateParam('nb_images', count($this->images));
87        }
88      }
89      else
90      {
91        throw new Exception(l10n('Invalid dowload set'));
92      }
93    }
94    // create a new set
95    else if ($set_id == 'new')
96    {
97      $this->data['type'] = $type;
98      $this->data['type_id'] = $type_id;
99     
100      $query = '
101INSERT INTO '.BATCH_DOWNLOAD_TSETS.'(
102    user_id,
103    date_creation,
104    type,
105    type_id,
106    nb_zip,
107    last_zip,
108    nb_images,
109    total_size,
110    status
111  )
112  VALUES(
113    '.$this->data['user_id'].',
114    NOW(),
115    "'.$this->data['type'].'",
116    "'.$this->data['type_id'].'",
117    0,
118    0,
119    0,
120    0,
121    "new"
122  )
123;';
124      pwg_query($query);
125      $this->data['id'] = pwg_db_insert_id();
126     
127      $date = pwg_query('SELECT FROM_UNIXTIME(NOW());');
128      list($this->data['date_creation']) = pwg_db_fetch_row($date);
129     
130      if (!empty($images))
131      {
132        $this->addImages($images);
133      }
134    }
135    else
136    {
137      trigger_error('BatchDownloader::__construct, invalid input parameter', E_USER_ERROR);
138    }
139  }
140 
141  /**
142   * updateParam
143   * @param: string param name
144   * @param: mixed param value
145   */
146  function updateParam($name, $value)
147  {
148    $this->data[$name] = $value;
149    pwg_query('UPDATE '.BATCH_DOWNLOAD_TSETS.' SET '.$name.' = "'.$value.'" WHERE id = '.$this->data['id'].';');
150  }
151 
152  /**
153   * getParam
154   * @param: string param name
155   * @return: mixed param value
156   */
157  function getParam($name)
158  {
159    return $this->data[$name];
160  }
161 
162  /**
163   * getImages
164   * @return: array
165   */
166  function getImages()
167  {
168    return $this->images;
169  }
170 
171  /**
172   * isInSet
173   * @param: int image id
174   * @return: bool
175   */
176  function isInSet($image_id)
177  {
178    return array_key_exists($image_id, $this->images);
179  }
180 
181  /**
182   * removeImages
183   * @param: array image ids
184   */
185  function removeImages($image_ids)
186  {
187    if (empty($image_ids) or !is_array($image_ids)) return;
188   
189    foreach ($image_ids as $image_id)
190    {
191      unset($this->images[ $image_id ]);
192    }
193   
194    $query = '
195DELETE FROM '.BATCH_DOWNLOAD_TIMAGES.'
196  WHERE
197    set_id = '.$this->data['id'].'
198    AND image_id IN('.implode(',', $image_ids).')
199;';
200    pwg_query($query);
201   
202    $this->updateParam('nb_images', count($this->images));
203  }
204 
205  /**
206   * addImages
207   * @param: array image ids
208   */
209  function addImages($image_ids)
210  {
211    if (empty($image_ids) or !is_array($image_ids)) return;
212   
213    $image_ids = array_unique($image_ids);
214    $inserts = array();
215   
216    foreach ($image_ids as $image_id)
217    {
218      if ($this->isInSet($image_id)) continue;
219     
220      $this->images[ $image_id ] = 0;
221      array_push($inserts, array('set_id'=>$this->data['id'], 'image_id'=>$image_id, 'zip'=>0));
222    }
223   
224    mass_inserts(
225      BATCH_DOWNLOAD_TIMAGES,
226      array('set_id', 'image_id', 'zip'),
227      $inserts
228      );
229     
230    $this->updateParam('nb_images', count($this->images));
231  }
232 
233  /**
234   * clearImages
235   */
236  function clearImages()
237  {
238    $this->images = array();
239   
240    $query = '
241DELETE FROM '.BATCH_DOWNLOAD_TIMAGES.'
242  WHERE set_id = '.$this->data['id'].'
243;';
244    pwg_query($query);
245  }
246 
247  /**
248   * deleteLastArchive
249   */
250  function deleteLastArchive()
251  {
252    $zip_path = $this->getArchivePath();
253    if (file_exists($zip_path))
254    {
255      unlink($zip_path);
256    }
257  }
258 
259  /**
260   * createNextArchive
261   * @param: bool force all elements in one archive
262   * @return: string zip path or false
263   */
264  function createNextArchive($force_one_archive=false)
265  {
266    // set already downloaded (we should never be there !)
267    if ( $this->data['status'] == 'done' or $this->data['nb_images'] == 0 )
268    {
269      trigger_error('BatchDownloader::createNextArchive, the set is empty', E_USER_ERROR);
270    }
271   
272    // first zip
273    if ($this->data['last_zip'] == 0)
274    {
275      $this->updateParam('status', 'download');
276     
277      // limit number of elements
278      if ($this->data['nb_images'] > $this->conf['max_elements'])
279      {
280        $images_ids = array_slice(array_keys($this->images), 0, $this->conf['max_elements']);
281        $this->clearImages();
282        $this->addImages($images_ids);
283      }
284     
285      $this->getEstimatedArchiveNumber();
286     
287      $this->updateParam('date_creation', date('Y-m-d H:i:s'));
288    }
289   
290    // get next images of the set
291    $images_to_add = array();
292    foreach ($this->images as $image_id => $zip_id)
293    {
294      if ($zip_id != 0) continue; // here are already added images
295      array_push($images_to_add, $image_id);
296    }
297   
298    if (count($images_to_add))
299    {
300      $query = '
301SELECT
302    id,
303    name,
304    file,
305    path,
306    filesize
307  FROM '.IMAGES_TABLE.'
308  WHERE id IN ('.implode(',', $images_to_add).')
309;';
310      $images_to_add = hash_from_query($query, 'id');
311     
312      // open zip
313      $this->updateParam('last_zip', $this->data['last_zip']+1);
314      $zip_path = $this->getArchivePath();
315     
316      $zip = new ZipArchive;
317      if ($zip->open($zip_path, ZipArchive::CREATE) !== true)
318      {
319        trigger_error('BatchDownloader::createNextArchive, unable to open ZIP archive', E_USER_ERROR);
320      }
321     
322      // add images until size limit is reach, or all images are added
323      $images_added = array();
324      $total_size = 0;
325      foreach ($images_to_add as $row)
326      {       
327        $zip->addFile(PHPWG_ROOT_PATH . $row['path'], $row['id'].'_'.str2url($row['name']).'.'.get_extension($row['file']));
328       
329        array_push($images_added, $row['id']);
330        $this->images[ $row['id'] ] = $this->data['last_zip'];
331       
332        $total_size+= $row['filesize'];
333        if ($total_size >= $this->conf['max_size']*1024 and !$force_one_archive) break;
334      }
335     
336      $this->updateParam('total_size', $this->data['total_size'] + $total_size);
337     
338      // archive comment
339      global $conf;
340      $comment = 'Generated on '.date('r').' with PHP ZipArchive '.PHP_VERSION.' by Piwigo Batch Downloader.';
341      $comment.= "\n".$conf['gallery_title'].' - '.get_absolute_root_url();
342      if (!empty($this->conf['archive_comment']))
343      {
344        $comment.= "\n\n".wordwrap(remove_accents($this->conf['archive_comment']), 60);
345      }
346      $zip->setArchiveComment($comment);
347     
348      $zip->close();
349     
350      // update database
351      $query = '
352UPDATE '.BATCH_DOWNLOAD_TIMAGES.'
353  SET zip = '.$this->data['last_zip'].'
354  WHERE
355    set_id = '.$this->data['id'].'
356    AND image_id IN('.implode(',', $images_added).')
357;';
358      pwg_query($query);
359     
360      // all images added ?
361      if (count($images_to_add) == count($images_added))
362      {
363        $this->updateParam('status', 'done');
364      }
365     
366      // over estimed
367      if ( $this->data['status'] == 'done' and $this->data['last_zip'] < $this->data['nb_zip'] )
368      {
369        $this->updateParam('nb_zip', $this->data['last_zip']);
370      }
371      // under estimed
372      else if ( $this->data['last_zip'] == $this->data['nb_zip'] and $this->data['status'] != 'done' )
373      {
374        $this->updateParam('nb_zip', $this->data['last_zip']+1);
375      }
376     
377      return $zip_path;
378    }
379    else
380    {
381      return false;
382    }
383  }
384 
385  /**
386   * getEstimatedTotalSize
387   * @return: int
388   */
389  function getEstimatedTotalSize()
390  {
391    if ($this->data['status'] == 'done') return $this->data['total_size'];
392    if ($this->data['nb_images'] == 0) return 0;
393   
394    $image_ids = array_slice(array_keys($this->images), 0, $this->conf['max_elements']);
395   
396    $query = '
397SELECT SUM(filesize) AS total
398  FROM '.IMAGES_TABLE.'
399  WHERE id IN ('.implode(',', $image_ids).')
400;';
401    list($total) = pwg_db_fetch_row(pwg_query($query));
402    return $total;
403  }
404 
405  /**
406   * getEstimatedArchiveNumber
407   * @return: int
408   */
409  function getEstimatedArchiveNumber()
410  {
411    $nb_zip = ceil( $this->getEstimatedTotalSize() / ($this->conf['max_size']*1024) );
412    $this->updateParam('nb_zip', $nb_zip);
413    return $nb_zip;
414  }
415 
416  /**
417   * getDownloadList
418   * @return: string html
419   */
420  function getDownloadList($url='')
421  {
422    if ($this->data['nb_images'] == 0)
423    {
424      return '<b>'.l10n('No archive').'</b>';
425    }
426   
427    $root_url = get_root_url();
428   
429    $out = '';
430    for ($i=1; $i<=$this->data['nb_zip']; $i++)
431    {
432      $out.= '<li id="zip-'.$i.'">';
433     
434      if ($this->data['status'] == 'done' or $i < $this->data['last_zip']+1)
435      {
436        $out.= '<img src="'.$root_url.BATCH_DOWNLOAD_PATH.'template/drive.png"> Archive #'.$i.' (already downloaded)';
437      }
438      else if ($i == $this->data['last_zip']+1)
439      {
440          $out.= '<a href="'.add_url_params($url, array('set_id'=>$this->data['id'],'zip'=>$i)).'" rel="nofollow" style="font-weight:bold;"' 
441            .($i!=1 ? 'onClick="return confirm(\'Starting download Archive #'.$i.' will destroy Archive #'.($i-1).', be sure you finish the download. Continue ?\');"' : null).
442            '><img src="'.$root_url.BATCH_DOWNLOAD_PATH.'template/drive_go.png"> Archive #'.$i.' (ready)</a>';
443      }
444      else
445      {
446        $out.= '<img src="'.$root_url.BATCH_DOWNLOAD_PATH.'template/drive.png"> Archive #'.$i.' (pending)';
447      }
448     
449      $out.= '</li>';
450    }
451   
452    return $out;
453  }
454 
455  /**
456   * getArchivePath
457   * @param: int archive number
458   * @return: string
459   */
460  function getArchivePath($i=null)
461  {
462    if (!file_exists(BATCH_DOWNLOAD_LOCAL . 'u-' .$this->data['user_id']. '/'))
463    {
464      mkdir(BATCH_DOWNLOAD_LOCAL . 'u-' .$this->data['user_id']. '/', 0755, true);
465    }
466   
467    if ($i === null) $i = $this->data['last_zip'];
468   
469    include_once(PHPWG_ROOT_PATH . 'admin/include/functions.php');
470   
471    return BATCH_DOWNLOAD_LOCAL .'u-'. $this->data['user_id'] .'/'.
472          (!empty($this->conf['archive_prefix']) ? $this->conf['archive_prefix'] .'_' : null).
473          get_username($this->data['user_id']) .'_'. 
474          $this->data['type'] .'-'. $this->data['type_id'] .'_'.
475          $this->data['user_id'] . $this->data['id'] .
476          ($this->data['nb_zip']!=1 ? '_part'. $i : null).
477          '.zip';
478  }
479 
480  /**
481   * getSetInfo
482   * @return: array
483   */
484  function getSetInfo()
485  {
486    $set = array(
487      'NB_IMAGES' => $this->data['nb_images'],
488      'NB_ARCHIVES' => $this->data['nb_zip'],
489      'TOTAL_SIZE' => ceil($this->getEstimatedTotalSize()/1024),
490      'LINKS' => $this->getDownloadList(BATCH_DOWNLOAD_PUBLIC . 'init_zip'),
491      'DATE_CREATION' => format_date($this->data['date_creation'], true),
492      );
493   
494    switch ($this->data['type'])
495    {
496      // calendar
497      case 'calendar':
498      {
499        global $conf, $page;
500        $old_page = $page;
501       
502        $fields = array(
503          'created' => l10n('Creation date'),
504          'posted' => l10n('Post date'),
505          );
506       
507        $chronology = explode('-', $this->data['type_id']);
508        $page['chronology_field'] = $chronology[0];
509        $page['chronology_style'] = $chronology[1];
510        $page['chronology_view'] = $chronology[2];
511        $page['chronology_date'] = array_splice($chronology, 3);
512       
513        if (!class_exists('Calendar'))
514        {
515          include_once(PHPWG_ROOT_PATH.'include/calendar_'. $page['chronology_style'] .'.class.php');
516        }
517        $calendar = new Calendar();
518        $calendar->initialize('');
519        $display_name = strip_tags($calendar->get_display_name());
520       
521        $set['NAME'] = l10n('Calendar').': '.$fields[$page['chronology_field']].$display_name;
522        $set['sNAME'] = l10n('Calendar').': '.ltrim($display_name, $conf['level_separator']);
523       
524        $page = $old_page;
525        break;
526      }
527     
528      // category
529      case 'category':
530      {
531        $category = get_cat_info($this->data['type_id']);
532        $set['NAME'] = l10n('Album').': '.get_cat_display_name($category['upper_names']);
533        $set['sNAME'] = l10n('Album').': '.trigger_event('render_category_name', $category['name']);
534        $set['COMMENT'] = trigger_event('render_category_description', $category['comment']);
535        break;
536      }
537     
538      // flat
539      case 'flat':
540      {
541        $set['NAME'] = l10n('Whole gallery');
542        break;
543      }
544     
545      // tags
546      case 'tags':
547      {
548        $tags = find_tags(explode(',', $this->data['type_id']));
549        $set['NAME'] = l10n('Tags').': ';
550       
551        $first = true;
552        foreach ($tags as $tag)
553        {
554          if ($first) $first = false;
555          else $set['NAME'].= ', ';
556          $set['NAME'].=
557            '<a href="' . make_index_url(array('tags'=>array($tag))) . '">'
558            .trigger_event('render_tag_name', $tag['name'])
559            .'</a>';
560        }
561        break;
562      }
563     
564      // search
565      case 'search':
566      {
567        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'search', 'search'=>$this->data['type_id'])).'">'.l10n('Search').'</a>';
568        break;
569      }
570     
571      // favorites
572      case 'favorites':
573      {
574        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'favorites')).'">'.l10n('Your favorites').'</a>';
575        break;
576      }
577     
578      // most_visited
579      case 'most_visited':
580      {
581        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'most_visited')).'">'.l10n('Most visited').'</a>';
582        break;
583      }
584     
585      // best_rated
586      case 'best_rated':
587      {
588        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'best_rated')).'">'.l10n('Best rated').'</a>';
589        break;
590      }
591     
592      // list
593      case 'list':
594      {
595        $set['NAME'] = l10n('Random');
596        break;
597      }
598     
599      // recent_pics
600      case 'recent_pics':
601      {
602        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'recent_pics')).'">'.l10n('Recent photos').'</a>';
603        break;
604      }
605     
606      // collection
607      case 'collection':
608      {
609        try
610        {
611          if (!class_exists('UserCollection')) throw new Exception();
612          $UserCollection = new UserCollection($this->data['type_id']);
613          $infos = $UserCollection->getCollectionInfo();
614          $set['NAME'] = l10n('Collection').': <a href="'.$infos['U_PUBLIC'].'">'.$UserCollection->getParam('name').'</a>';
615        }
616        catch (Exception $e)
617        {
618          $set['NAME'] = l10n('Collection').': #'.$this->data['type_id'].' (deleted)';
619        }
620        break;
621      }
622    }
623   
624    if (!isset($set['sNAME'])) $set['sNAME'] = strip_tags($set['NAME']);
625    if (!isset($set['COMMENT'])) $set['COMMENT'] = null;
626   
627    return $set;
628  }
629}
630
631?>
Note: See TracBrowser for help on using the repository browser.