1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8/**
9 * Tiki_Profile_List
10 *
11 */
12class Tiki_Profile_List
13{
14	function getSources()
15	{
16		global $prefs;
17		$raw = explode("\n", $prefs['profile_sources']);
18		$raw = array_map('trim', $raw);
19		$sources = [];
20
21		foreach ($raw as $source) {
22			if (! empty($source)) {
23				$file = $this->getCacheLocation($source);
24				$last = $this->getCacheLastUpdate($source);
25				$short = dirname($source);
26				$sources[] = [
27					'url' => $source,
28					'domain' => (0 === strpos($short, 'http://')) ? substr($short, 7) : $short,
29					'short' => $short,
30					'status' => ($last && filesize($file)) ? 'open' : 'closed',
31					'lastupdate' => $last,
32					'formatted' => $last ? date('Y-m-d H:i:s', $last) : '' ];
33			}
34		}
35
36		return $sources;
37	}
38
39	function refreshCache($path)
40	{
41		global $tikilib;
42		$file = $this->getCacheLocation($path);
43
44		// Replace existing with blank file
45		if (file_exists($file)) {
46			unlink($file);
47		}
48		touch($file);
49
50		$content = $tikilib->httprequest($path);
51
52		$parts = explode("\n", $content);
53		$parts = array_map('trim', $parts);
54		$good = false;
55
56		foreach ($parts as $line) {
57			// All lines contain 3 entries
58			if (empty($line)) {
59				continue;
60			}
61			if (substr_count($line, "\t") != 2) {
62				return false;
63			}
64
65			$good = true;
66		}
67
68		// A valid file has at least one profile
69		if (! $good) {
70			return false;
71		}
72
73		file_put_contents($file, $content . "\n");
74
75		return true;
76	}
77
78	function getCategoryList($source = '')
79	{
80		$category_list = [];
81
82		$sources = $this->getSources();
83
84		foreach ($sources as $s) {
85			if ($source && $s['url'] != $source) {
86				continue;
87			}
88
89			if (! $s['lastupdate']) {
90				continue;
91			}
92
93			$fp = fopen($this->getCacheLocation($s['url']), 'r');
94
95			while (false !== $row = fgetcsv($fp, 200, "\t")) {
96				$c = $row[0];
97				if ($c) {
98					$category_list[] = $c;
99				}
100			}
101		}
102
103		natsort($category_list);
104		return(array_unique($category_list));
105	}
106
107	function getList($source = '', $categories = [], $profilename = '')
108	{
109		$installer = new Tiki_Profile_Installer;
110		$list = [];
111
112		$sources = $this->getSources();
113
114		foreach ($sources as $s) {
115			if ($source && $s['url'] != $source) {
116				continue;
117			}
118
119			if (! $s['lastupdate']) {
120				continue;
121			}
122
123			$fp = fopen($this->getCacheLocation($s['url']), 'r');
124
125			while (false !== $row = fgetcsv($fp, 200, "\t")) {
126				if (count($row) != 3) {
127					continue;
128				}
129
130				list($c, $t, $i) = $row;
131
132				$key = "{$s['url']}#{$i}";
133
134				if ($profilename && stripos($i, $profilename) === false) {
135					continue;
136				}
137
138				if (array_key_exists($key, $list)) {
139					$list[$key]['categories'][] = $c;
140				} else {
141					$list[$key] = [
142							'domain' => $s['domain'],
143							'categories' => [$c],
144							'name' => $i,
145							'installed' => $installer->isKeyInstalled($s['domain'], $i),
146							];
147				}
148			}
149
150			fclose($fp);
151
152			// Apply category filter
153			foreach ($list as $pkey => $profile) {
154				$in = true; // If there are no required categories, don't filter anything.
155				if (! empty($categories)) {
156					foreach ($categories as $category) {
157						$in = false; // Start assuming this required category isn't in this profile's categories
158						foreach ($profile['categories'] as $pcategory) {
159							if ($category == $pcategory) {
160								$in = true;
161								break;
162							}
163						}
164						if (! $in) {
165							break;
166						}
167					}
168				}
169				if (! $in) {
170					unset($list[$pkey]);
171				}
172			}
173		}
174
175		return array_values($list);
176	}
177
178	private function getCacheLocation($path)
179	{
180		$hash = md5($path);
181		return "temp/cache/profile$hash";
182	}
183
184	private function getCacheLastUpdate($path)
185	{
186		$file = $this->getCacheLocation($path);
187		if (! file_exists($file)) {
188			return 0;
189		}
190
191		return filemtime($file);
192	}
193}
194