1<?php
2/**
3 * Coppermine Photo Gallery
4 *
5 * v1.0 originally written by Gregory Demar
6 *
7 * @copyright  Copyright (c) 2003-2018 Coppermine Dev Team
8 * @license    GNU General Public License version 3 or later; see LICENSE
9 *
10 * include/upgrader.inc.php
11 * @since  1.6.06
12 */
13defined('IN_COPPERMINE') or die('Not in Coppermine...');
14
15class CPG_Updater
16{
17	protected $updates = array();
18
19	public function __construct ($quiet=false, $no_pre=true)
20	{
21		global $lang_update_php;
22
23		$releases = json_decode($this->getUrlData('https://api.github.com/repos/coppermine-gallery/cpg1.6.x/releases'));
24		if (!$releases) {
25			if ($quiet) return;
26			cpg_die(ERROR, $lang_update_php['not_found']?:'Releases of CPG not found at Github', __FILE__, __LINE__);
27		}
28		foreach ($releases as $r) {
29			if ($r->prerelease && $no_pre) continue;	// don't offer any prereleases
30			$tag = $r->tag_name;
31			if (preg_match('/\d+\.\d+\.\d+/', $tag, $m)) {
32				if (version_compare($m[0], COPPERMINE_VERSION) == 1) {
33					$this->updates[] = array(
34						'id' => $r->id,
35						'tag' => $m[0],
36						'pre' => $r->prerelease,
37						'ball' => $r->zipball_url,
38						'name' => $r->name,
39						'body' => nl2br($r->body)
40						);
41				}
42			}
43		}
44	}
45
46	public function getUpdates ()
47	{
48		return $this->updates;
49	}
50
51	public function performUpdate ($id)
52	{
53		global $lang_update_php;
54
55		$updt = null;
56		foreach ($this->updates as $u) {
57			if ($u['id'] == $id) {
58				$updt = $u;
59				break;
60			}
61		}
62		if (!$updt) return;
63
64		unlink(UPDATER_LOG);
65		$this->logIt("UPDATING TO: {$updt['tag']}");
66		$tmpf = (sys_get_temp_dir() ?: 'albums/edit').'/cpg_upd_'.time().'.zip';
67		$newUpdate = $this->getUrlData($updt['ball']);
68		$dlHandler = fopen($tmpf, 'w');
69		if (!fwrite($dlHandler, $newUpdate)) { cpg_die(ERROR, $lang_update_php['save_error'], __FILE__, __LINE__); }
70		fclose($dlHandler);
71
72		$f2p = array('include/config.inc.php','anycontent.php');	//files to preserve if they already exist
73		$p2s = array('albums/');	//paths to skip (whether they exist or not)
74		$zip = new ZipArchive;
75		$res = $zip->open($tmpf);
76		if ($res === TRUE) {
77			for ($i = 0; $i < $zip->numFiles; $i++ ) {
78				$stat = $zip->statIndex($i);
79				list($bd,$fp) = explode('/', $stat['name'], 2);
80				if (substr($fp, -1) == '/') {
81					if ($this->matchedPath($fp, $p2s)) continue;
82					if (!is_dir($fp)) @mkdir($fp);
83					$this->logIt("DIR: {$fp}");
84				} elseif ($fp) {
85					if (in_array($fp, $f2p) && file_exists($fp)) continue;
86					if ($this->matchedPath($fp, $p2s)) continue;
87					$fc = $zip->getFromIndex($i);
88					file_put_contents($fp, $fc);
89					$this->logIt("PUT: {$fp}");
90				}
91			}
92			$zip->close();
93		} else {
94			echo 'failed, code:' . $res;
95		}
96
97		unlink($tmpf);
98	}
99
100	public function __toString ()
101	{
102		return print_r($this->updates, true);
103	}
104
105	public function checkCpgDirs ()
106	{
107		$cpgDirs = array('albums','bridge','css','images','include','js','lang','logs','plugins','sql','themes');
108		$ng = array();
109		foreach ($cpgDirs as $dir) {
110			if (!(is_dir($dir) && is_writable($dir))) $ng[] = $dir;
111		}
112		return $ng;
113	}
114
115	private function getUrlData ($url)
116	{
117		$ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14';
118		if (ini_get('allow_url_fopen')) {
119			ini_set('user_agent', $ua);
120			$rfc = file_get_contents($url);
121			if (!$rfc) return $this->curly($url, $ua);
122			return $rfc;
123		} else {
124			return $this->curly($url, $ua);
125		}
126	}
127
128	private function curly ($url, $agent)
129	{
130		if (!extension_loaded('libcurl')) return '';
131		// create curl resource
132		$ch = curl_init();
133		// set url
134		curl_setopt($ch, CURLOPT_URL, $url);
135		//return the transfer as a string
136		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
137		curl_setopt($ch, CURLOPT_USERAGENT, $agent);
138		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
139		// $output contains the output string
140		$output = curl_exec($ch);
141		// close curl resource to free up system resources
142		curl_close($ch);
143		// return the data
144		return $output;
145	}
146
147	private function matchedPath ($file, $paths)
148	{
149		foreach ($paths as $p) {
150			$p = str_replace('/','\/',$p);
151			if (preg_match("/^{$p}/", $file)) return true;
152		}
153		return false;
154	}
155
156	private function logIt ($msg)
157	{
158		file_put_contents(UPDATER_LOG, "{$msg}\n", FILE_APPEND);
159	}
160
161}
162//EOF