Changeset 3730:5c45a5df9a59 for inc/core/class.dc.store.php
- Timestamp:
- 03/08/18 17:58:39 (7 years ago)
- Branch:
- default
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
inc/core/class.dc.store.php
r3025 r3730 10 10 # 11 11 # -- END LICENSE BLOCK ----------------------------------------- 12 if (!defined('DC_RC_PATH')) { return;}12 if (!defined('DC_RC_PATH')) {return;} 13 13 14 14 /** … … 18 18 19 19 Provides an object to parse XML feed of modules from repository. 20 */20 */ 21 21 class dcStore 22 22 { 23 /** @var object dcCore instance */ 24 public $core; 25 /** @var object dcModules instance */ 26 public $modules; 27 28 /** @var array Modules fields to search on and their weighting */ 29 public static $weighting = array('id' => 10, 'name' => 8, 'author' => 6, 'tags' => 4, 'desc' => 2); 30 31 /** @var string User agent used to query repository */ 32 protected $user_agent = 'DotClear.org RepoBrowser/0.1'; 33 /** @var string XML feed URL */ 34 protected $xml_url; 35 /** @var array Array of new/update modules from repository */ 36 protected $data; 37 38 /** 39 * Constructor. 40 * 41 * @param object $modules dcModules instance 42 * @param string $xml_url XML feed URL 43 */ 44 public function __construct(dcModules $modules, $xml_url) 45 { 46 $this->core = $modules->core; 47 $this->modules = $modules; 48 $this->xml_url = $xml_url; 49 $this->user_agent = sprintf('Dotclear/%s)', DC_VERSION); 50 51 $this->check(); 52 } 53 54 /** 55 * Check repository. 56 * 57 * @param boolean $force Force query repository 58 * @return boolean True if get feed or cache 59 */ 60 public function check($force=false) 61 { 62 if (!$this->xml_url) { 63 return false; 64 } 65 if (($parser = dcStoreReader::quickParse($this->xml_url, DC_TPL_CACHE, $force)) === false) { 66 return false; 67 } 68 69 $raw_datas = $parser->getModules(); 70 71 uasort($raw_datas, array('self','sort')); 72 73 $skipped = array_keys($this->modules->getDisabledModules()); 74 foreach ($skipped as $p_id) { 75 if (isset($raw_datas[$p_id])) { 76 unset($raw_datas[$p_id]); 77 } 78 } 79 80 $updates = array(); 81 $current = $this->modules->getModules(); 82 foreach ($current as $p_id => $p_infos) { 83 if (isset($raw_datas[$p_id])) { 84 if (dcUtils::versionsCompare($raw_datas[$p_id]['version'],$p_infos['version'],'>')) { 85 $updates[$p_id] = $raw_datas[$p_id]; 86 $updates[$p_id]['root'] = $p_infos['root']; 87 $updates[$p_id]['root_writable'] = $p_infos['root_writable']; 88 $updates[$p_id]['current_version'] = $p_infos['version']; 89 } 90 unset($raw_datas[$p_id]); 91 } 92 } 93 94 $this->data = array( 95 'new' => $raw_datas, 96 'update' => $updates 97 ); 98 99 return true; 100 } 101 102 /** 103 * Get a list of modules. 104 * 105 * @param boolean $update True to get update modules, false for new ones 106 * @return array List of update/new modules 107 */ 108 public function get($update=false) 109 { 110 return $this->data[$update ? 'update' : 'new']; 111 } 112 113 /** 114 * Search a module. 115 * 116 * Search string is cleaned, split and compare to split: 117 * - module id and clean id, 118 * - module name, clean name, 119 * - module desccription. 120 * 121 * Every time a part of query is find on module, 122 * result accuracy grow. Result is sorted by accuracy. 123 * 124 * @param string $pattern String to search 125 * @return array Match modules 126 */ 127 public function search($pattern) 128 { 129 $result = array(); 130 131 # Split query into small clean words 132 if (!($patterns = self::patternize($pattern))) { 133 return $result; 134 } 135 136 # For each modules 137 foreach ($this->data['new'] as $id => $module) { 138 $module['id'] = $id; 139 140 # Loop through required module fields 141 foreach(self::$weighting as $field => $weight) { 142 143 # Skip fields which not exsist on module 144 if (empty($module[$field])) { 145 continue; 146 } 147 148 # Split field value into small clean word 149 if (!($subjects = self::patternize($module[$field]))) { 150 continue; 151 } 152 153 # Check contents 154 if (!($nb = preg_match_all('/('.implode('|', $patterns).')/', implode(' ', $subjects), $_))) { 155 continue; 156 } 157 158 # Add module to result 159 if (!isset($sorter[$id])) { 160 $sorter[$id] = 0; 161 $result[$id] = $module; 162 } 163 164 # Increment score by matches count * field weight 165 $sorter[$id] += $nb * $weight; 166 $result[$id]['score'] = $sorter[$id]; 167 } 168 } 169 # Sort response by matches count 170 if (!empty($result)) { 171 array_multisort($sorter, SORT_DESC, $result); 172 } 173 return $result; 174 } 175 176 /** 177 * Quick download and install module. 178 * 179 * @param string $url Module package URL 180 * @param string $dest Path to install module 181 * @return integer 1 = installed, 2 = update 182 */ 183 public function process($url, $dest) 184 { 185 $this->download($url, $dest); 186 return $this->install($dest); 187 } 188 189 /** 190 * Download a module. 191 * 192 * @param string $url Module package URL 193 * @param string $dest Path to put module package 194 */ 195 public function download($url, $dest) 196 { 197 // Check and add default protocol if necessary 198 if (!preg_match('%^http[s]?:\/\/%',$url)) { 199 $url = 'http://'.$url; 200 } 201 // Download package 202 if ($client = netHttp::initClient($url, $path)) { 203 try { 204 $client->setUserAgent($this->user_agent); 205 $client->useGzip(false); 206 $client->setPersistReferers(false); 207 $client->setOutput($dest); 208 $client->get($path); 209 unset($client); 210 } 211 catch (Exception $e) { 212 unset($client); 213 throw new Exception(__('An error occurred while downloading the file.')); 214 } 215 } else { 216 throw new Exception(__('An error occurred while downloading the file.')); 217 } 218 } 219 220 /** 221 * Install a previously downloaded module. 222 * 223 * @param string $path Module package URL 224 * @param string $path Path to module package 225 * @return integer 1 = installed, 2 = update 226 */ 227 public function install($path) 228 { 229 return dcModules::installPackage($path, $this->modules); 230 } 231 232 /** 233 * User Agent String. 234 * 235 * @param string $str User agent string 236 */ 237 public function agent($str) 238 { 239 $this->user_agent = $str; 240 } 241 242 /** 243 * Split and clean pattern. 244 * 245 * @param string $str String to sanitize 246 * @return array Array of cleaned pieces of string or false if none 247 */ 248 public static function patternize($str) 249 { 250 $arr = array(); 251 252 foreach(explode(' ', $str) as $_) { 253 $_ = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $_)); 254 if (strlen($_) > 2) { 255 $arr[] = $_; 256 } 257 } 258 259 return empty($arr) ? false : $arr; 260 } 261 262 /** 263 * Compare version. 264 * 265 * @param string $v1 Version 266 * @param string $v2 Version 267 * @param string $op Comparison operator 268 * @return boolean True is comparison is true, dude! 269 */ 270 private static function compare($v1, $v2, $op) 271 { 272 return version_compare( 273 preg_replace('!-r(\d+)$!', '-p$1', $v1), 274 preg_replace('!-r(\d+)$!', '-p$1', $v2), 275 $op 276 ); 277 } 278 279 /** 280 * Sort modules list. 281 * 282 * @param array $a A module 283 * @param array $b A module 284 * @return integer 285 */ 286 private static function sort($a,$b) 287 { 288 $c = strtolower($a['id']); 289 $d = strtolower($b['id']); 290 if ($c == $d) { 291 return 0; 292 } 293 return ($c < $d) ? -1 : 1; 294 } 23 /** @var object dcCore instance */ 24 public $core; 25 /** @var object dcModules instance */ 26 public $modules; 27 28 /** @var array Modules fields to search on and their weighting */ 29 public static $weighting = array('id' => 10, 'name' => 8, 'author' => 6, 'tags' => 4, 'desc' => 2); 30 31 /** @var string User agent used to query repository */ 32 protected $user_agent = 'DotClear.org RepoBrowser/0.1'; 33 /** @var string XML feed URL */ 34 protected $xml_url; 35 /** @var array Array of new/update modules from repository */ 36 protected $data; 37 38 /** 39 * Constructor. 40 * 41 * @param object $modules dcModules instance 42 * @param string $xml_url XML feed URL 43 */ 44 public function __construct(dcModules $modules, $xml_url) 45 { 46 $this->core = $modules->core; 47 $this->modules = $modules; 48 $this->xml_url = $xml_url; 49 $this->user_agent = sprintf('Dotclear/%s)', DC_VERSION); 50 51 $this->check(); 52 } 53 54 /** 55 * Check repository. 56 * 57 * @param boolean $force Force query repository 58 * @return boolean True if get feed or cache 59 */ 60 public function check($force = false) 61 { 62 if (!$this->xml_url) { 63 return false; 64 } 65 if (($parser = dcStoreReader::quickParse($this->xml_url, DC_TPL_CACHE, $force)) === false) { 66 return false; 67 } 68 69 $raw_datas = $parser->getModules(); 70 71 uasort($raw_datas, array('self', 'sort')); 72 73 $skipped = array_keys($this->modules->getDisabledModules()); 74 foreach ($skipped as $p_id) { 75 if (isset($raw_datas[$p_id])) { 76 unset($raw_datas[$p_id]); 77 } 78 } 79 80 $updates = array(); 81 $current = $this->modules->getModules(); 82 foreach ($current as $p_id => $p_infos) { 83 if (isset($raw_datas[$p_id])) { 84 if (dcUtils::versionsCompare($raw_datas[$p_id]['version'], $p_infos['version'], '>')) { 85 $updates[$p_id] = $raw_datas[$p_id]; 86 $updates[$p_id]['root'] = $p_infos['root']; 87 $updates[$p_id]['root_writable'] = $p_infos['root_writable']; 88 $updates[$p_id]['current_version'] = $p_infos['version']; 89 } 90 unset($raw_datas[$p_id]); 91 } 92 } 93 94 $this->data = array( 95 'new' => $raw_datas, 96 'update' => $updates 97 ); 98 99 return true; 100 } 101 102 /** 103 * Get a list of modules. 104 * 105 * @param boolean $update True to get update modules, false for new ones 106 * @return array List of update/new modules 107 */ 108 public function get($update = false) 109 { 110 return $this->data[$update ? 'update' : 'new']; 111 } 112 113 /** 114 * Search a module. 115 * 116 * Search string is cleaned, split and compare to split: 117 * - module id and clean id, 118 * - module name, clean name, 119 * - module desccription. 120 * 121 * Every time a part of query is find on module, 122 * result accuracy grow. Result is sorted by accuracy. 123 * 124 * @param string $pattern String to search 125 * @return array Match modules 126 */ 127 public function search($pattern) 128 { 129 $result = array(); 130 131 # Split query into small clean words 132 if (!($patterns = self::patternize($pattern))) { 133 return $result; 134 } 135 136 # For each modules 137 foreach ($this->data['new'] as $id => $module) { 138 $module['id'] = $id; 139 140 # Loop through required module fields 141 foreach (self::$weighting as $field => $weight) { 142 143 # Skip fields which not exsist on module 144 if (empty($module[$field])) { 145 continue; 146 } 147 148 # Split field value into small clean word 149 if (!($subjects = self::patternize($module[$field]))) { 150 continue; 151 } 152 153 # Check contents 154 if (!($nb = preg_match_all('/(' . implode('|', $patterns) . ')/', implode(' ', $subjects), $_))) { 155 continue; 156 } 157 158 # Add module to result 159 if (!isset($sorter[$id])) { 160 $sorter[$id] = 0; 161 $result[$id] = $module; 162 } 163 164 # Increment score by matches count * field weight 165 $sorter[$id] += $nb * $weight; 166 $result[$id]['score'] = $sorter[$id]; 167 } 168 } 169 # Sort response by matches count 170 if (!empty($result)) { 171 array_multisort($sorter, SORT_DESC, $result); 172 } 173 return $result; 174 } 175 176 /** 177 * Quick download and install module. 178 * 179 * @param string $url Module package URL 180 * @param string $dest Path to install module 181 * @return integer 1 = installed, 2 = update 182 */ 183 public function process($url, $dest) 184 { 185 $this->download($url, $dest); 186 return $this->install($dest); 187 } 188 189 /** 190 * Download a module. 191 * 192 * @param string $url Module package URL 193 * @param string $dest Path to put module package 194 */ 195 public function download($url, $dest) 196 { 197 // Check and add default protocol if necessary 198 if (!preg_match('%^http[s]?:\/\/%', $url)) { 199 $url = 'http://' . $url; 200 } 201 // Download package 202 if ($client = netHttp::initClient($url, $path)) { 203 try { 204 $client->setUserAgent($this->user_agent); 205 $client->useGzip(false); 206 $client->setPersistReferers(false); 207 $client->setOutput($dest); 208 $client->get($path); 209 unset($client); 210 } catch (Exception $e) { 211 unset($client); 212 throw new Exception(__('An error occurred while downloading the file.')); 213 } 214 } else { 215 throw new Exception(__('An error occurred while downloading the file.')); 216 } 217 } 218 219 /** 220 * Install a previously downloaded module. 221 * 222 * @param string $path Module package URL 223 * @param string $path Path to module package 224 * @return integer 1 = installed, 2 = update 225 */ 226 public function install($path) 227 { 228 return dcModules::installPackage($path, $this->modules); 229 } 230 231 /** 232 * User Agent String. 233 * 234 * @param string $str User agent string 235 */ 236 public function agent($str) 237 { 238 $this->user_agent = $str; 239 } 240 241 /** 242 * Split and clean pattern. 243 * 244 * @param string $str String to sanitize 245 * @return array Array of cleaned pieces of string or false if none 246 */ 247 public static function patternize($str) 248 { 249 $arr = array(); 250 251 foreach (explode(' ', $str) as $_) { 252 $_ = strtolower(preg_replace('/[^A-Za-z0-9]/', '', $_)); 253 if (strlen($_) > 2) { 254 $arr[] = $_; 255 } 256 } 257 258 return empty($arr) ? false : $arr; 259 } 260 261 /** 262 * Compare version. 263 * 264 * @param string $v1 Version 265 * @param string $v2 Version 266 * @param string $op Comparison operator 267 * @return boolean True is comparison is true, dude! 268 */ 269 private static function compare($v1, $v2, $op) 270 { 271 return version_compare( 272 preg_replace('!-r(\d+)$!', '-p$1', $v1), 273 preg_replace('!-r(\d+)$!', '-p$1', $v2), 274 $op 275 ); 276 } 277 278 /** 279 * Sort modules list. 280 * 281 * @param array $a A module 282 * @param array $b A module 283 * @return integer 284 */ 285 private static function sort($a, $b) 286 { 287 $c = strtolower($a['id']); 288 $d = strtolower($b['id']); 289 if ($c == $d) { 290 return 0; 291 } 292 return ($c < $d) ? -1 : 1; 293 } 295 294 }
Note: See TracChangeset
for help on using the changeset viewer.