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

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