source: extensions/autoupdate/branches/1.7/include/functions.inc.php @ 6205

Last change on this file since 6205 was 6205, checked in by patdenice, 14 years ago

Piwigo AutoUpgrade ready for 1.7.x versions.

File size: 14.9 KB
Line 
1<?php
2
3if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
4
5function autoupdate_deltree($path, $move_to_trash=false)
6{
7  if (is_dir($path))
8  {
9    $fh = opendir($path);
10    while ($file = readdir($fh))
11    {
12      if ($file != '.' and $file != '..')
13      {
14        $pathfile = $path . '/' . $file;
15        if (is_dir($pathfile))
16        {
17          autoupdate_deltree($pathfile, $move_to_trash);
18        }
19        else
20        {
21          @unlink($pathfile);
22        }
23      }
24    }
25    closedir($fh);
26    if (@rmdir($path))
27    {
28      return true;
29    }
30    elseif ($move_to_trash)
31    {
32      $trash = PHPWG_ROOT_PATH.'_trash';
33      if (!is_dir($trash))
34      {
35        @mkgetdir($trash);
36      }
37      return @rename($path, $trash . '/'.md5(uniqid(rand(), true)));
38    }
39    else
40    {
41      return false;
42    }
43  }
44}
45
46function autoupdate_add_index($path)
47{
48  if (is_dir($path))
49  {
50    $fh = opendir($path);
51    while ($file = readdir($fh))
52    {
53      if ($file != '.' and $file != '..')
54      {
55        $pathfile = $path . '/' . $file;
56        if (is_dir($pathfile))
57        {
58          autoupdate_add_index($pathfile);
59        }
60      }
61    }
62    $fp = @fopen($path.'/index.php', 'w');
63    @fwrite($fp, AU_DEFAULT_INDEX);
64    @fclose($fp);
65    closedir($fh);
66  }
67}
68
69function process_obsolete_list($file)
70{
71  if (file_exists(PHPWG_ROOT_PATH.$file)
72    and $old_files = file(PHPWG_ROOT_PATH.$file, FILE_IGNORE_NEW_LINES)
73    and !empty($old_files))
74  {
75    array_push($old_files, $file);
76    foreach($old_files as $old_file)
77    {
78      $path = PHPWG_ROOT_PATH.$old_file;
79      if (is_file($path))
80      {
81        @unlink($path);
82      }
83      elseif (is_dir($path))
84      {
85        autoupdate_deltree($path, true);
86      }
87    }
88  }
89}
90
91function move_local_files($dir)
92{
93  global $page, $cfgBase, $cfgUser, $cfgPassword, $cfgHote, $prefixeTable;
94
95  if ((!is_dir($dir) and !mkdir($dir, 0777))
96    or (!is_dir($dir.'/config') and !mkdir($dir.'/config'))
97    or (!is_dir($dir.'/css') and !mkdir($dir.'/css'))
98    or (!is_dir($dir.'/language') and !mkdir($dir.'/language')))
99  {
100    autoupdate_deltree($dir);
101    array_push($page['errors'], l10n('Unable to write new local directory.'));
102    return;
103  }
104
105  // Add index.php
106  autoupdate_add_index($dir);
107
108  // mysql.inc.php
109  $file = PHPWG_ROOT_PATH.'include/mysql.inc.php';
110  if (is_readable($file))
111  {
112    $file_content = '<?php
113$conf[\'dblayer\'] = \'mysql\';
114$conf[\'db_base\'] = \''.$cfgBase.'\';
115$conf[\'db_user\'] = \''.$cfgUser.'\';
116$conf[\'db_password\'] = \''.$cfgPassword.'\';
117$conf[\'db_host\'] = \''.$cfgHote.'\';
118
119$prefixeTable = \''.$prefixeTable.'\';
120
121define(\'PHPWG_INSTALLED\', true);';
122    if (defined('PWG_CHARSET'))
123    {
124      $file_content.= '
125define(\'PWG_CHARSET\', \'utf-8\');
126define(\'DB_CHARSET\', \'utf8\');
127define(\'DB_COLLATE\', \'\');';
128    }
129    $file_content.= '
130?>';
131    $new_config_file = $dir.'/config/database.inc.php';
132
133    if (!($fp = @fopen($new_config_file, 'w'))
134      or !@fwrite($fp, $file_content)
135      or !@fclose($fp))
136    {
137      array_push($page['errors'], l10n('Unable to write new local directory.'));
138      return;
139    }
140    @chmod($new_config_file, 0755);
141  }
142
143  // config_local.inc.php
144  $file = PHPWG_ROOT_PATH.'include/config_local.inc.php';
145  if (is_readable($file))
146  {
147    copy($file, $dir.'/config/config.inc.php');
148    @chmod($file, 0755);
149  }
150
151  // languages
152  $language_dir = opendir(PHPWG_ROOT_PATH.'language');
153  while ($file = readdir($language_dir))
154  {
155    $path = PHPWG_ROOT_PATH.'language/'.$file;
156    if (!is_link($path) and is_dir($path) and is_readable($path.'/local.lang.php'))
157    {
158      $content = file_get_contents($path.'/local.lang.php');
159      $langdef = explode('.',$file);
160      if (count($langdef)>1)
161      {
162        $content = utf8_encode($content);
163      }
164      $filename = $dir.'/language/'.$langdef[0].'.lang.php';
165      $fp = @fopen($filename, 'w');
166      @fwrite($fp, $content);
167      @fclose($fp);
168      @chmod($filename, 0755);
169    }
170  }
171  closedir($language_dir);
172
173  // template-common/local-layout.css
174  $file = PHPWG_ROOT_PATH.'template-common/local-layout.css';
175  if (is_readable($file))
176  {
177    copy($file, $dir.'/css/rules.css');
178    @chmod($file, 0755);
179  }
180
181  // template/xxx/local-layout.css
182  $known_templates = array(
183    'yoga'     => 'default',
184    'floPure'  => 'Pure_default',
185    'floOs'    => 'OS_default',
186    'gally'    => 'gally-default',
187    'simple'   => 'simple',
188  );
189
190  foreach ($known_templates as $old_tpl => $new_tpl)
191  {
192    $file = PHPWG_ROOT_PATH.'template/'.$old_tpl.'/local-layout.css';
193    if (is_readable($file))
194    {
195      copy($file, $dir.'/css/'.$new_tpl.'-rules.css');
196      @chmod($file, 0755);
197    }
198  }
199}
200
201function autoupdate_save_template_dir()
202{
203  global $page, $conf;
204
205  $path = $conf['local_data_dir'].'/autoupdate';
206
207  if (mkgetdir($path)
208    and ($zip = tempnam($path, 'zip'))
209    and ($archive = new pclZip($zip))
210    and ($v_list = $archive->add(PHPWG_ROOT_PATH.'template', PCLZIP_OPT_REMOVE_PATH, PHPWG_ROOT_PATH))
211    and is_array($v_list)
212    and !empty($v_list))
213  {
214    $http_headers = array(
215      'Content-Length: '.@filesize($zip),
216      'Content-Type: application/zip',
217      'Content-Disposition: attachment; filename="template.zip";',
218      'Content-Transfer-Encoding: binary',
219      );
220
221    foreach ($http_headers as $header) {
222      header($header);
223    }
224
225    @readfile($zip);
226    autoupdate_deltree($conf['local_data_dir'].'/autoupdate');
227    exit();
228  }
229  else
230  {
231    array_push($page['errors'], l10n('Unable to send template directory.'));
232  }
233}
234
235function autoupdate_dump_database()
236{
237  global $page, $conf, $cfgBase;
238
239  if (version_compare(PHPWG_VERSION, '2.1', '<'))
240  {
241    $conf['db_base'] = $cfgBase;
242  }
243
244  include(AUTOUPDATE_PATH.'include/mysqldump.php');
245
246  $path = $conf['local_data_dir'].'/autoupdate';
247
248  if (@mkgetdir($path)
249    and ($backupFile = tempnam($path, 'sql'))
250    and ($dumper = new MySQLDump($conf['db_base'],$backupFile,false,false)))
251  {
252    foreach (get_defined_constants() as $constant => $value)
253    {
254      if (preg_match('/_TABLE$/', $constant))
255      {
256        $dumper->getTableStructure($value);
257
258        if ($constant == 'HISTORY_TABLE' and !isset($_POST['includeHistory']))
259        {
260          continue;
261        }
262
263        $dumper->getTableData($value);
264      }
265    }
266  }
267
268  if (@filesize($backupFile))
269  {
270    $http_headers = array(
271      'Content-Length: '.@filesize($backupFile),
272      'Content-Type: text/x-sql',
273      'Content-Disposition: attachment; filename="database.sql";',
274      'Content-Transfer-Encoding: binary',
275      );
276
277    foreach ($http_headers as $header) {
278      header($header);
279    }
280
281    @readfile($backupFile);
282    autoupdate_deltree($conf['local_data_dir'].'/autoupdate');
283    exit();
284  }
285  else
286  {
287    array_push($page['errors'], l10n('Unable to dump database.'));
288  }
289}
290
291function autoupdate_upgrade_to($upgrade_to, &$step)
292{
293  global $page, $conf, $template;
294
295  if (!version_compare($_POST['upgrade_to'], PHPWG_VERSION, '>'))
296  {
297    redirect(get_admin_plugin_menu_link(AUTOUPDATE_PATH . '/autoupdate.php'));
298  }
299
300  if ($step == 2)
301  {
302    preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches);
303    $code =  $matches[1].'.x_to_'.$_POST['upgrade_to'];
304    $dl_code = str_replace(array('.', '_'), '', $code);
305    $remove_path = $code;
306    $obsolete_list = 'obsolete.list';
307  }
308  else
309  {
310    $code = $_POST['upgrade_to'];
311    $dl_code = $code;
312    $remove_path = version_compare($code, '2.0.8', '>=') ? 'piwigo' : 'piwigo-'.$code;
313    $obsolete_list = PHPWG_ROOT_PATH.'install/obsolete.list';
314
315    move_local_files(PHPWG_ROOT_PATH.'local');
316  }
317
318  if (empty($page['errors']))
319  {
320    $path = $conf['local_data_dir'].'/autoupdate';
321    $filename = $path.'/'.$code.'.zip';
322    @mkgetdir($path);
323
324    $chunk_num = 0;
325    $end = false;
326    $zip = @fopen($filename, 'w');
327    while (!$end)
328    {
329      $chunk_num++;
330      if (@fetchRemote('http://piwigo.org/download/dlcounter.php?code='.$dl_code.'&chunk_num='.$chunk_num, $result)
331        and $input = @unserialize($result))
332      {
333        if (0 == $input['remaining'])
334        {
335          $end = true;
336        }
337        @fwrite($zip, base64_decode($input['data']));
338      }
339      else
340      {
341        $end = true;
342      }
343    }
344    @fclose($zip);
345
346    if (@filesize($filename))
347    {
348      $zip = new PclZip($filename);
349      if ($result = $zip->extract(PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
350                                  PCLZIP_OPT_REMOVE_PATH, $remove_path,
351                                  PCLZIP_OPT_SET_CHMOD, 0755,
352                                  PCLZIP_OPT_REPLACE_NEWER))
353      {
354        //Check if all files were extracted
355        $error = '';
356        foreach($result as $extract)
357        {
358          if (!in_array($extract['status'], array('ok', 'filtered', 'already_a_directory')))
359          {
360            // Try to change chmod and extract
361            if (@chmod(PHPWG_ROOT_PATH.$extract['filename'], 0777)
362              and ($res = $zip->extract(PCLZIP_OPT_BY_NAME, $remove_path.'/'.$extract['filename'],
363                                        PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
364                                        PCLZIP_OPT_REMOVE_PATH, $remove_path,
365                                        PCLZIP_OPT_SET_CHMOD, 0755,
366                                        PCLZIP_OPT_REPLACE_NEWER))
367              and isset($res[0]['status'])
368              and $res[0]['status'] == 'ok')
369            {
370              continue;
371            }
372            else
373            {
374              $error .= $extract['filename'].': '.$extract['status']."\n";
375            }
376          }
377        }
378
379        if (empty($error))
380        {
381          process_obsolete_list($obsolete_list);
382          autoupdate_deltree($conf['local_data_dir'].'/autoupdate');
383          invalidate_user_cache(true);
384          if ($step == 2)
385          {
386            array_push($page['infos'], sprintf(l10n('autoupdate_success'), $upgrade_to));
387            $step = 3;
388          }
389          else
390          {
391            redirect(PHPWG_ROOT_PATH.'upgrade.php?now=');
392          }
393        }
394        else
395        {
396          $logfile = @fopen($conf['local_data_dir'].'/autoupdate/log_error.txt', 'w');
397          @fwrite($logfile, $error);
398          @fclose($logfile);
399          $relative_path = trim(str_replace(dirname(dirname(dirname(dirname(__FILE__)))), '', $conf['local_data_dir']), '/\\');
400          array_push($page['errors'], sprintf(l10n('autoupdate_extract_fail'), PHPWG_ROOT_PATH.$relative_path.'/autoupdate/log_error.txt'));
401        }
402      }
403      else
404      {
405        autoupdate_deltree($conf['local_data_dir'].'/autoupdate');
406        array_push($page['errors'], l10n('autoupdate_fail'));
407      }
408    }
409    else
410    {
411      array_push($page['errors'], l10n('Piwigo cannot retrieve upgrade file from server'));
412    }
413  }
414}
415
416function is_webmaster($user_status = '')
417{
418  return is_autorize_status(ACCESS_WEBMASTER, $user_status);
419}
420
421/**
422 * Retrieve data from external URL
423 *
424 * @param string $src: URL
425 * @param global $dest: can be a file ressource or string
426 * @return bool
427 */
428function fetchRemote($src, &$dest, $user_agent='Piwigo', $step=0)
429{
430  // Try to retrieve data from local file?
431  if (!url_is_remote($src))
432  {
433    $content = @file_get_contents($src);
434    if ($content !== false)
435    {
436      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
437      return true;
438    }
439    else
440    {
441      return false;
442    }
443  }
444
445  // After 3 redirections, return false
446  if ($step > 3) return false;
447
448  // Initialize $dest
449  is_resource($dest) or $dest = '';
450
451  // Try curl to read remote file
452  if (function_exists('curl_init'))
453  {
454    $ch = @curl_init();
455    @curl_setopt($ch, CURLOPT_URL, $src);
456    @curl_setopt($ch, CURLOPT_HEADER, 1);
457    @curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
458    @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
459    $content = @curl_exec($ch);
460    $header_length = @curl_getinfo($ch, CURLINFO_HEADER_SIZE);
461    $status = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
462    @curl_close($ch);
463    if ($content !== false and $status >= 200 and $status < 400)
464    {
465      if (preg_match('/Location:\s+?(.+)/', substr($content, 0, $header_length), $m))
466      {
467        return fetchRemote($m[1], $dest, $user_agent, $step+1);
468      }
469      $content = substr($content, $header_length);
470      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
471      return true;
472    }
473  }
474
475  // Try file_get_contents to read remote file
476  if (ini_get('allow_url_fopen'))
477  {
478    $content = @file_get_contents($src);
479    if ($content !== false)
480    {
481      is_resource($dest) ? @fwrite($dest, $content) : $dest = $content;
482      return true;
483    }
484  }
485
486  // Try fsockopen to read remote file
487  $src = parse_url($src);
488  $host = $src['host'];
489  $path = isset($src['path']) ? $src['path'] : '/';
490  $path .= isset($src['query']) ? '?'.$src['query'] : '';
491
492  if (($s = @fsockopen($host,80,$errno,$errstr,5)) === false)
493  {
494    return false;
495  }
496
497  fwrite($s,
498    "GET ".$path." HTTP/1.0\r\n"
499    ."Host: ".$host."\r\n"
500    ."User-Agent: ".$user_agent."\r\n"
501    ."Accept: */*\r\n"
502    ."\r\n"
503  );
504
505  $i = 0;
506  $in_content = false;
507  while (!feof($s))
508  {
509    $line = fgets($s);
510
511    if (rtrim($line,"\r\n") == '' && !$in_content)
512    {
513      $in_content = true;
514      $i++;
515      continue;
516    }
517    if ($i == 0)
518    {
519      if (!preg_match('/HTTP\/(\\d\\.\\d)\\s*(\\d+)\\s*(.*)/',rtrim($line,"\r\n"), $m))
520      {
521        fclose($s);
522        return false;
523      }
524      $status = (integer) $m[2];
525      if ($status < 200 || $status >= 400)
526      {
527        fclose($s);
528        return false;
529      }
530    }
531    if (!$in_content)
532    {
533      if (preg_match('/Location:\s+?(.+)$/',rtrim($line,"\r\n"),$m))
534      {
535        fclose($s);
536        return fetchRemote(trim($m[1]),$dest,$user_agent,$step+1);
537      }
538      $i++;
539      continue;
540    }
541    is_resource($dest) ? @fwrite($dest, $line) : $dest .= $line;
542    $i++;
543  }
544  fclose($s);
545  return true;
546}
547
548define('MKGETDIR_NONE', 0);
549define('MKGETDIR_RECURSIVE', 1);
550define('MKGETDIR_DIE_ON_ERROR', 2);
551define('MKGETDIR_PROTECT_INDEX', 4);
552define('MKGETDIR_PROTECT_HTACCESS', 8);
553define('MKGETDIR_DEFAULT', 7);
554/**
555 * creates directory if not exists; ensures that directory is writable
556 * @param:
557 *  string $dir
558 *  int $flags combination of MKGETDIR_xxx
559 * @return bool false on error else true
560 */
561function mkgetdir($dir, $flags=MKGETDIR_DEFAULT)
562{
563  if ( !is_dir($dir) )
564  {
565    $umask = umask(0);
566    $mkd = @mkdir($dir, 0755, ($flags&MKGETDIR_RECURSIVE) ? true:false );
567    umask($umask);
568    if ($mkd==false)
569    {
570      !($flags&MKGETDIR_DIE_ON_ERROR) or fatal_error( "$dir ".l10n('no write access'));
571      return false;
572    }
573    if( $flags&MKGETDIR_PROTECT_HTACCESS )
574    {
575      $file = $dir.'/.htaccess';
576      file_exists($file) or @file_put_contents( $file, 'deny from all' );
577    }
578    if( $flags&MKGETDIR_PROTECT_INDEX )
579    {
580      $file = $dir.'/index.htm';
581      file_exists($file) or @file_put_contents( $file, 'Not allowed!' );
582    }
583  }
584  if ( !is_writable($dir) )
585  {
586    !($flags&MKGETDIR_DIE_ON_ERROR) or fatal_error( "$dir ".l10n('no write access'));
587    return false;
588  }
589  return true;
590}
591
592define('AU_DEFAULT_INDEX', file_get_contents(AUTOUPDATE_PATH.'index.php'));
593?>
Note: See TracBrowser for help on using the repository browser.