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

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

first commit, not complete
TODO : use multisize, download history, localization, compatibility with User Selection (and create User Selection !!)

File size: 14.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->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()
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) 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      }
361     
362      // over estimed
363      if ( $this->data['status'] == 'done' and $this->data['last_zip'] < $this->data['nb_zip'] )
364      {
365        $this->updateParam('nb_zip', $this->data['last_zip']);
366      }
367      // under estimed
368      else if ( $this->data['last_zip'] == $this->data['nb_zip'] and $this->data['status'] != 'done' )
369      {
370        $this->updateParam('nb_zip', $this->data['last_zip']+1);
371      }
372     
373      return $zip_path;
374    }
375    else
376    {
377      return false;
378    }
379  }
380 
381  /**
382   * getEstimatedTotalSize
383   * @return: int
384   */
385  function getEstimatedTotalSize()
386  {
387    if ($this->data['nb_images'] == 0) return 0;
388   
389    $image_ids = array_slice(array_keys($this->images), 0, $this->conf['max_elements']);
390   
391    $query = '
392SELECT SUM(filesize) AS total
393  FROM '.IMAGES_TABLE.'
394  WHERE id IN ('.implode(',', $image_ids).')
395;';
396    list($total) = pwg_db_fetch_row(pwg_query($query));
397    return $total;
398  }
399 
400  /**
401   * getEstimatedArchiveNumber
402   * @return: int
403   */
404  function getEstimatedArchiveNumber()
405  {
406    $nb_zip = ceil( $this->getEstimatedTotalSize() / ($this->conf['max_size']*1024) );
407    $this->updateParam('nb_zip', $nb_zip);
408    return $nb_zip;
409  }
410 
411  /**
412   * getDownloadList
413   * @return: string html
414   */
415  function getDownloadList($url='')
416  {
417    $nb_archives = $this->getEstimatedArchiveNumber();
418   
419    $out = '<ul id="download_list">';
420    if ($this->data['status'] == 'done')
421    {
422      $out.= '<li id="zip-1">Already downloaded</li>';
423    }
424    else
425    {
426      for ($i=1; $i<=$this->data['nb_zip']; $i++)
427      {
428        $out.= '<li id="zip-'.$i.'">';
429       
430        if ($i < $this->data['last_zip']+1)
431        {
432          $out.= 'Archive #'.$i.' (already downloaded)';
433        }
434        else if ($i == $this->data['last_zip']+1)
435        {
436            $out.= '<a href="'.add_url_params($url, array('set_id'=>$this->data['set_id'],'zip'=>$i)).'" rel="nofollow"' 
437              .($i!=1 ? 'onClick="return confirm(\'Starting download Archive #'.$i.' will destroy Archive #'.($i-1).', be sure you finish the download. Continue ?\');"' : null).
438              '>Archive #'.$i.' (ready)</a>';
439        }
440        else
441        {
442          $out.= 'Archive #'.$i.' (pending)';
443        }
444       
445        $out.= '</li>';
446      }
447    }
448    $out.= '</ul>';
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          'part'. $i .'.zip';
475  }
476 
477  /**
478   * getSetInfo
479   * @return: array
480   */
481  function getSetInfo()
482  {
483    $set = array(
484      'NB_IMAGES' => $this->data['nb_images'],
485      'NB_ARCHIVES' => $this->data['nb_zip'],
486      'TOTAL_SIZE' => ceil($this->getEstimatedTotalSize()/1024),
487      'LINKS' => $this->getDownloadList(BATCH_DOWNLOAD_PUBLIC . 'init_zip'),
488      );
489       
490    if ($this->data['status'] == 'new')
491    {
492      $set['U_EDIT_SET'] = BATCH_DOWNLOAD_PUBLIC . 'view&amp;set_id='.$this->data['set_id'];
493    }
494   
495    switch ($this->data['type'])
496    {
497      case 'calendar':
498      {
499        $set['NAME'] = l10n('Calendar');
500        $set['COMMENT'] = $this->data['type_id'];
501        break;
502      }
503     
504      case 'category':
505      {
506        $category = get_cat_info($this->data['type_id']);
507        $set['NAME'] = get_cat_display_name($category['upper_names']);
508        $set['sNAME'] = $category['name'];
509        $set['COMMENT'] = trigger_action('render_category_description', $category['comment']);
510        break;
511      }
512     
513      case 'flat':
514      {
515        $set['NAME'] = l10n('Whole gallery');
516        break;
517      }
518     
519      case 'tags':
520      {
521        $tags = find_tags(explode(',', $this->data['type_id']));
522        $set['NAME'] = l10n('Tags');
523       
524        $set['COMMENT'] = ''; $first = true;
525        foreach ($tags as $tag)
526        {
527          if ($first) $first = false;
528          else $set['COMMENT'].= ', ';
529          $set['COMMENT'].=
530            '<a href="' . make_index_url(array('tags'=>array($tag))) . '">'
531            .trigger_event('render_tag_name', $tag['name'])
532            .'</a>';
533        }
534        break;
535      }
536     
537      case 'search':
538      {
539        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'search', 'search'=>$this->data['type_id'])).'">'.l10n('Search').'</a>';
540        break;
541      }
542     
543      case 'favorites':
544      {
545        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'favorites')).'">'.l10n('Your favorites').'</a>';
546        break;
547      }
548     
549      case 'most_visited':
550      {
551        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'most_visited')).'">'.l10n('Most visited').'</a>';
552        break;
553      }
554     
555      case 'best_rated':
556      {
557        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'best_rated')).'">'.l10n('Best rated').'</a>';
558        break;
559      }
560     
561      case 'list':
562      {
563        $set['NAME'] = l10n('Random');
564        break;
565      }
566     
567      case 'recent_pics':
568      {
569        $set['NAME'] = '<a href="'.make_index_url(array('section'=>'recent_pics')).'">'.l10n('Recent photos').'</a>';
570        break;
571      }
572     
573      // case 'selection':
574      // {
575        // $set['NAME'] = '';
576        // $set['COMMENT'] = '';
577        // break;
578      // }
579    }
580   
581    if (!isset($set['sNAME'])) $set['sNAME'] = $set['NAME'];
582    if (!isset($set['COMMENT'])) $set['COMMENT'] = null;
583   
584    return $set;
585  }
586}
587
588?>
Note: See TracBrowser for help on using the repository browser.