PageRenderTime 32ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Mage/Connect/Singleconfig.php

https://gitlab.com/blingbang2016/shop
PHP | 865 lines | 637 code | 49 blank | 179 comment | 32 complexity | fb56f7ad8dfe2432f40533cd890f7d46 MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magento.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magento.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Connect
  23. * @copyright Copyright (c) 2006-2016 X.commerce, Inc. and affiliates (http://www.magento.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Class to manipulate with channel/package cache file
  28. *
  29. * @category Mage
  30. * @package Mage_Connect
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_Connect_Singleconfig
  34. {
  35. /**
  36. * Cache data
  37. * @var array
  38. */
  39. protected $_data = array();
  40. /**
  41. * Filename
  42. * @var string
  43. */
  44. protected $_readFilename = false;
  45. /**
  46. *
  47. * @var unknown_type
  48. */
  49. protected $_debug = false;
  50. /**
  51. *
  52. * @var unknown_type
  53. */
  54. protected $_validator;
  55. /**
  56. * Internal keys constants
  57. */
  58. const K_CHAN = 'channels_by_name';
  59. const K_CHAN_URI = 'channels_by_uri';
  60. const K_CHAN_ALIAS = 'channel_aliases';
  61. const K_PACK = 'packages';
  62. const K_URI = 'uri';
  63. const K_CHAN_DATA = 'channel_data';
  64. const K_NAME = 'name';
  65. const K_VER = 'version';
  66. const K_STATE = 'stability';
  67. const K_XML = 'xml';
  68. const K_DEPS = 'deps';
  69. const K_PACK_DEPS = 'pack_deps';
  70. const K_CONFIG = 'config';
  71. public function getValidUri($str)
  72. {
  73. $data = @parse_url($str);
  74. if(isset($data['path'])) {
  75. return $data['path'];
  76. }
  77. return false;
  78. }
  79. public function getFilename()
  80. {
  81. return $this->_readFilename;
  82. }
  83. public function formatUri($uri)
  84. {
  85. $uri = rtrim($uri, "/");
  86. $uri = str_replace("http://", '', $uri);
  87. $uri = str_replace("ftp://", '', $uri);
  88. return $uri;
  89. }
  90. /**
  91. * Get data
  92. * @return unknown_type
  93. */
  94. public function getData()
  95. {
  96. return $this->_data;
  97. }
  98. /**
  99. * Constructor
  100. * @param srting $file
  101. * @return void
  102. */
  103. public function __construct($file = "cache.cfg")
  104. {
  105. $this->setEmptyConfig();
  106. if($file) {
  107. $this->_readFilename = $file;
  108. $this->load();
  109. }
  110. }
  111. /**
  112. * Load cache from file
  113. * @param string $file
  114. * @return void
  115. */
  116. public function load($file = false)
  117. {
  118. if(false === $file) {
  119. $file = $this->_readFilename;
  120. }
  121. if(false === $file) {
  122. return;
  123. }
  124. if(!file_exists($file)) {
  125. $this->save($file);
  126. return;
  127. }
  128. if(!is_readable($file)) {
  129. return $this->doError("File is not readable: '{$file}'");
  130. }
  131. $this->_readFilename = $file;
  132. $data = @file_get_contents($file);
  133. if(false === $data) {
  134. return $this->doError("Cannot get file contents: '{$file}'");
  135. }
  136. if(!$this->_debug) {
  137. $data = @gzuncompress($data);
  138. if(false === $data) {
  139. return $this->doError("Cannot unpack gzipped data in file contents: '{$file}'");
  140. }
  141. }
  142. $data = @unserialize($data);
  143. if(unserialize(false) === $data) {
  144. return $this->doError("Cannot unserialize data in file contents: '{$file}'");
  145. }
  146. $validData = true;
  147. foreach(array_keys($this->_data) as $k) {
  148. if(!isset($data[$k])) {
  149. $validData = false;
  150. } else {
  151. $this->_data[$k] = $data[$k];
  152. }
  153. }
  154. if($validData) {
  155. $this->_data = $data;
  156. } else {
  157. $this->save();
  158. }
  159. }
  160. /**
  161. * Save contents
  162. * @param string $file
  163. * @return void
  164. */
  165. public function save($file = false)
  166. {
  167. if(false === $file) {
  168. $file = $this->_readFilename;
  169. }
  170. if(false === $file) {
  171. return;
  172. }
  173. $data = @serialize($this->_data);
  174. if(!$this->_debug) {
  175. $data = @gzcompress($data);
  176. }
  177. $res = @file_put_contents($file, $data);
  178. if(!$res) {
  179. $this->doError("Cannot save: '{$file}'");
  180. }
  181. }
  182. /**
  183. * Set empty config skeleton
  184. * @return void
  185. */
  186. public function setEmptyConfig()
  187. {
  188. $this->_data = array(
  189. self::K_CHAN => array (),
  190. self::K_CHAN_URI => array (),
  191. self::K_CHAN_ALIAS => array (),
  192. );
  193. }
  194. public function isChannel($chanName)
  195. {
  196. if($this->isChannelName($chanName)) {
  197. return true;
  198. }
  199. if($this->isChannelUri($chanName)) {
  200. return true;
  201. }
  202. if($this->isChannelAlias($chanName)) {
  203. return true;
  204. }
  205. return false;
  206. }
  207. /**
  208. * Get channel
  209. * @param string $chanName
  210. * @return array
  211. */
  212. public function getChannel($chanName)
  213. {
  214. if($this->isChannelAlias($chanName)) {
  215. $chanName = $this->getChannelNameByAlias($chanName);
  216. } elseif($this->isChannelUri($chanName)) {
  217. $chanName = $this->getChannelUriRecord($chanName);
  218. }
  219. if($this->isChannelName($chanName)) {
  220. return $this->_data[self::K_CHAN][$chanName];
  221. }
  222. }
  223. /**
  224. * Is channel name?
  225. * @param $chanName
  226. * @return bool
  227. */
  228. public function isChannelName($chanName)
  229. {
  230. return isset($this->_data[self::K_CHAN][$chanName]);
  231. }
  232. /**
  233. * Is channel alias?
  234. * @param string $chanName
  235. * @return bool
  236. */
  237. public function isChannelAlias($chanName)
  238. {
  239. return isset($this->_data[self::K_CHAN_ALIAS][$chanName]);
  240. }
  241. /**
  242. * Is channel uri?
  243. * @param $uri
  244. * @return bool
  245. */
  246. public function isChannelUri($uri)
  247. {
  248. $uri = $this->formatUri($uri);
  249. return isset($this->_data[self::K_CHAN_URI][$uri]);
  250. }
  251. /**
  252. * Unset channel uri record
  253. * @param string $uri
  254. * @return void
  255. */
  256. protected function unsetChannelUriRecord($uri)
  257. {
  258. $uri = $this->formatUri($uri);
  259. unset($this->_data[self::K_CHAN_URI][$uri]);
  260. }
  261. /**
  262. * Set channel uri record: uri maps to channel record
  263. * @param string $chanName
  264. * @param string $uri
  265. * @return void
  266. */
  267. protected function setChannelUriRecord($chanName, $uri)
  268. {
  269. $uri = $this->formatUri($uri);
  270. $this->_data[self::K_CHAN_URI][$uri] = $chanName;
  271. }
  272. /**
  273. * Get channel name by uri record
  274. * @param string $uri
  275. * @return string
  276. */
  277. protected function getChannelUriRecord($uri)
  278. {
  279. $uri = $this->formatUri($uri);
  280. return $this->_data[self::K_CHAN_URI][$uri];
  281. }
  282. /**
  283. * Unset channel record
  284. * @param string $chanName
  285. * @return void
  286. */
  287. protected function unsetChannelRecord($chanName)
  288. {
  289. unset($this->_data[self::K_CHAN][$chanName]);
  290. }
  291. /**
  292. * Get channel record
  293. * @param string $chanName
  294. * @return array
  295. */
  296. protected function getChannelRecord($chanName)
  297. {
  298. return $this->_data[self::K_CHAN][$chanName];
  299. }
  300. /**
  301. * Set channel record
  302. * @param string $chanName
  303. * @param string $uri
  304. * @param mixed $data
  305. * @param array $packages
  306. * @return void
  307. */
  308. protected function setChannelRecord($chanName, $uri, $data, $packages = array())
  309. {
  310. $this->_data[self::K_CHAN][$chanName] = array(
  311. self::K_NAME=>$chanName,
  312. self::K_URI=>$uri,
  313. self::K_CHAN_DATA=>$data,
  314. self::K_PACK=>$packages
  315. );
  316. }
  317. /**
  318. * Set package record
  319. * @param string $chanName
  320. * @param string $packageName
  321. * @param mixed $data
  322. * @return void
  323. */
  324. protected function setPackageRecord($chanName, $packageName, $data, $oneField = null)
  325. {
  326. if(null === $oneField) {
  327. $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName] = $data;
  328. } else {
  329. $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName][$oneField] = $data;
  330. }
  331. }
  332. /**
  333. * Unset package record
  334. * @param string $chanName
  335. * @param string $packageName
  336. * @return void
  337. */
  338. protected function unsetPackageRecord($chanName, $packageName)
  339. {
  340. unset($this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName]);
  341. }
  342. /**
  343. * Get package record
  344. * @param string $chanName
  345. * @param string $packageName
  346. * @return array
  347. */
  348. protected function fetchPackage($chanName, $packageName, $field = null)
  349. {
  350. if(null === $field) {
  351. return $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName];
  352. } else {
  353. return $this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName][$field];
  354. }
  355. }
  356. /**
  357. * Has package record
  358. * @param string $chanName
  359. * @param string $packageName
  360. * @return bool
  361. */
  362. protected function hasPackageRecord($chanName, $packageName)
  363. {
  364. return isset($this->_data[self::K_CHAN][$chanName][self::K_PACK][$packageName]);
  365. }
  366. /**
  367. * Get channel name by alias
  368. * @param string $alias
  369. * @return array
  370. */
  371. protected function getChannelNameByAlias($alias)
  372. {
  373. return $this->_data[self::K_CHAN_ALIAS][$alias];
  374. }
  375. /**
  376. * Set channel alias
  377. * @param string $alias
  378. * @param string $chanName
  379. * @return void
  380. */
  381. protected function setChannelAlias($alias, $chanName)
  382. {
  383. $this->_data[self::K_CHAN_ALIAS][$alias] = $chanName;
  384. }
  385. /**
  386. * Unset channel alias
  387. * @param string $alias
  388. * @return void
  389. */
  390. protected function unsetChannelAlias($alias)
  391. {
  392. unset($this->_data[self::K_CHAN_ALIAS][$alias]);
  393. }
  394. /**
  395. * Clear all aliases of channel
  396. * @param string $chanName channel name
  397. * @return void
  398. */
  399. protected function clearAliases($chanName)
  400. {
  401. $keys = array_keys($this->_data[self::K_CHAN_ALIAS]);
  402. foreach ($keys as $key) {
  403. if($this->_data[self::K_CHAN_ALIAS][$key] == $chanName) {
  404. unset($this->_data[self::K_CHAN_ALIAS][$key]);
  405. }
  406. }
  407. }
  408. /**
  409. * Add channel alias
  410. * @param string $chanName
  411. * @param string $alias
  412. * @return void
  413. */
  414. public function addChannelAlias($chanName, $alias)
  415. {
  416. if($this->isChannelName($alias)) {
  417. return $this->doError("Alias '{$alias}' is existant channel name!");
  418. }
  419. if(!$this->isChannelName($chanName)) {
  420. return $this->doError("Channel '{$chanName}' doesn't exist");
  421. }
  422. $this->setChannelAlias($alias, $chanName);
  423. $this->save();
  424. }
  425. /**
  426. * Add channel
  427. * @param $chanName
  428. * @param $uri
  429. * @param $data
  430. * @return void
  431. */
  432. public function addChannel($chanName, $uri, $data = array())
  433. {
  434. if($this->isChannelName($chanName)) {
  435. return $this->doError("Channel '{$chanName}' already exist!");
  436. }
  437. if($this->isChannelUri($uri)) {
  438. return $this->doError("Channel with uri= '{$uri}' already exist!");
  439. }
  440. if($this->isChannelAlias($chanName)) {
  441. $this->unsetChannelAlias($chanName);
  442. }
  443. $uri = $this->formatUri($uri);
  444. $this->setChannelRecord($chanName, $uri, $data);
  445. $this->setChannelUriRecord($chanName, $uri);
  446. $this->save();
  447. }
  448. /**
  449. * Delete channel
  450. * @param $chanName
  451. * @return void
  452. */
  453. public function deleteChannel($chanName)
  454. {
  455. if($this->isChannelName($chanName)) {
  456. $record = $this->getChannelRecord($chanName);
  457. $this->unsetChannelUriRecord($record[self::K_URI]);
  458. $this->unsetChannelRecord($chanName);
  459. $this->clearAliases($chanName);
  460. } elseif($this->isChannelUri($chanName)) {
  461. $uri = $chanName;
  462. $chanName = $this->getChannelUriRecord($uri);
  463. $this->unsetChannelUriRecord($uri);
  464. $this->unsetChannelRecord($chanName);
  465. $this->clearAliases($chanName);
  466. } elseif($this->isChannelAlias($chanName)) {
  467. $this->unsetChannelAlias($chanName);
  468. } else {
  469. return $this->doError("'{$chanName}' was not found in aliases, channel names, channel uris");
  470. }
  471. $this->save();
  472. }
  473. /**
  474. * Converts channel name, url or alias to channel name
  475. * throws exception if not found
  476. * @param srting $chanName
  477. * @return string
  478. */
  479. public function chanName($chanName)
  480. {
  481. $channelData = $this->getChannel($chanName);
  482. if(!$channelData) {
  483. return $this->doError("Channel '{$chanName}' doesn't exist");
  484. }
  485. return $channelData[self::K_NAME];
  486. }
  487. public function chanUrl($chan)
  488. {
  489. $channelData = $this->getChannel($chan);
  490. if(!$channelData) {
  491. return $this->doError("Channel '{$chan}' doesn't exist");
  492. }
  493. return $channelData[self::K_URI];
  494. }
  495. /**
  496. * Add package
  497. * @param Mage_Connect_Package $package
  498. * @return void
  499. */
  500. public function addPackage($package)
  501. {
  502. $channel = $this->chanName($package->getChannel());
  503. $name = $package->getName();
  504. $record = array (
  505. self::K_VER => $package->getVersion(),
  506. self::K_STATE => $package->getStability(),
  507. self::K_XML => $package->getPackageXml(),
  508. self::K_NAME => $name,
  509. self::K_DEPS => array(),
  510. self::K_PACK_DEPS => array(),
  511. );
  512. $this->setPackageRecord($channel, $name, $record);
  513. $this->setPackageDependencies($channel, $name, $package->getDependencyPackages());
  514. $this->save();
  515. }
  516. /**
  517. * Delete package
  518. * @param string $chanName
  519. * @param string $package
  520. * @return void
  521. */
  522. public function deletePackage($chanName, $package)
  523. {
  524. $chanName = $this->chanName($chanName);
  525. $this->unsetPackageRecord($chanName, $package);
  526. $this->save();
  527. }
  528. /**
  529. * Get package
  530. * @param sting $chanName
  531. * @param string $package
  532. * @return void
  533. */
  534. public function getPackage($chanName, $package)
  535. {
  536. $chanName = $this->chanName($chanName);
  537. if($this->hasPackageRecord($chanName, $package)) {
  538. return $this->fetchPackage($chanName, $package);
  539. }
  540. return null;
  541. }
  542. public function getPackageObject($chanName, $package)
  543. {
  544. $chanName = $this->chanName($chanName);
  545. if($this->hasPackageRecord($chanName, $package)) {
  546. $data = $this->fetchPackage($chanName, $package);
  547. return new Mage_Connect_Package($data[self::K_XML]);
  548. }
  549. throw new Exception("Cannot get package: '{$package}'");
  550. }
  551. public function hasPackage($chanName, $package, $versionMin = false, $versionMax = false)
  552. {
  553. $chanName = $this->chanName($chanName);
  554. $data = $this->getPackage($chanName, $package);
  555. if(null === $data) {
  556. return false;
  557. }
  558. $installedVersion = $data[self::K_VER];
  559. return $this->versionInRange($installedVersion, $versionMin, $versionMax);
  560. }
  561. public function versionInRange($version, $versionMin = false, $versionMax = false)
  562. {
  563. if(false === $versionMin) {
  564. $minOk = true;
  565. } else {
  566. $minOk = version_compare($version, $versionMin, ">=");
  567. }
  568. if(false === $versionMax) {
  569. $maxOk = true;
  570. } else {
  571. $maxOk = version_compare($version, $versionMax, "<=");
  572. }
  573. return $minOk && $maxOk;
  574. }
  575. public function hasVersionRangeIntersect($min1, $max1, $min2, $max2)
  576. {
  577. if(version_compare($min1, $min2, ">") && version_compare($max1, $max2, ">")) {
  578. return false;
  579. } elseif(version_compare($min1, $min2, "<") && version_compare($max1, $max2, "<")) {
  580. return false;
  581. } elseif(version_compare($min1, $min2, ">=") && version_compare($max1, $max2, "<=")) {
  582. return true;
  583. } elseif(version_compare($min1, $min2, "<=") && version_compare($max1, $max2, ">=")) {
  584. return true;
  585. }
  586. return false;
  587. }
  588. /**
  589. * Clear contents to defaults and save
  590. * @return void
  591. */
  592. public function clear()
  593. {
  594. $this->setEmptyConfig();
  595. $this->save();
  596. }
  597. /**
  598. * Output error - throw exception
  599. * @param $message
  600. * @throws Exception
  601. * @return void
  602. */
  603. protected function doError($message)
  604. {
  605. throw new Exception($message);
  606. }
  607. public function compareStabilities($s1, $s2)
  608. {
  609. if(!$this->_validator) {
  610. $this->_validator = new Mage_Connect_Validator();
  611. }
  612. return $this->_validator->compareStabilities($s1, $s2);
  613. }
  614. public function detectVersionFromRestArray($restData, $argVersionMin = false, $argVersionMax = false, $preferredStability = 'devel')
  615. {
  616. if(!is_array($restData)) {
  617. return false;
  618. }
  619. foreach($restData as $vData) {
  620. $stability = trim($vData['s']);
  621. $version = trim($vData['v']);
  622. $goodStability = $this->compareStabilities($stability, $preferredStability) >= 0;
  623. if($goodStability && $this->versionInRange($version, $argVersionMin, $argVersionMax)) {
  624. return $version;
  625. }
  626. }
  627. return false;
  628. }
  629. public function setPackageDependencies($chanName, $package, $data)
  630. {
  631. $chanName = $this->chanName($chanName);
  632. if($this->hasPackageRecord($chanName, $package)) {
  633. $this->setPackageRecord($chanName, $package, $data, self::K_PACK_DEPS);
  634. $this->save();
  635. return true;
  636. }
  637. return false;
  638. }
  639. public function getPackageDependencies($chanName, $package)
  640. {
  641. $chanName = $this->chanName($chanName);
  642. if($this->hasPackageRecord($chanName, $package)) {
  643. return $this->fetchPackage($chanName, $package, self::K_PACK_DEPS);
  644. }
  645. return false;
  646. }
  647. public function setDependencyInfo($chanName, $package, $data)
  648. {
  649. $chanName = $this->chanName($chanName);
  650. if($this->hasPackageRecord($chanName, $package)) {
  651. $this->setPackageRecord($chanName, $package, $data, self::K_DEPS);
  652. $this->save();
  653. return true;
  654. }
  655. return false;
  656. }
  657. public function getDependencyInfo($chanName, $package)
  658. {
  659. $chanName = $this->chanName($chanName);
  660. if($this->hasPackageRecord($chanName, $package)) {
  661. return $this->fetchPackage($chanName, $package, self::K_DEPS);
  662. }
  663. return false;
  664. }
  665. public function getChannelNames()
  666. {
  667. return array_keys($this->_data[self::K_CHAN]);
  668. }
  669. public function getPackagesData($channel = false)
  670. {
  671. if(false == $channel) {
  672. return $this->_data[self::K_CHAN];
  673. }
  674. if(!$this->isChannel($channel)) {
  675. return array();
  676. }
  677. return $this->getChannel($channel);
  678. }
  679. public function specifiedInDependencyList($deps, $chanName, $packageName)
  680. {
  681. foreach($deps as $dep) {
  682. if($chanName == $dep['channel'] && $packageName == $dep['name']) {
  683. return true;
  684. }
  685. }
  686. return false;
  687. }
  688. public function requiredByOtherPackages($chanName, $packageName, $excludeList = array())
  689. {
  690. $out = array();
  691. foreach($this->_data[self::K_CHAN] as $channel=>$data) {
  692. foreach($data[self::K_PACK] as $package) {
  693. if($this->specifiedInDependencyList($excludeList, $channel, $package['name'])) {
  694. continue;
  695. }
  696. $deps = $package[self::K_PACK_DEPS];
  697. if($this->specifiedInDependencyList($deps, $chanName, $packageName)) {
  698. $out[] = array('channel'=>$channel, 'name' =>$package['name'], 'version'=>$package['version']);
  699. }
  700. }
  701. }
  702. return $out;
  703. }
  704. public function getInstalledPackages($chanName = false)
  705. {
  706. if(false == $chanName) {
  707. $data = $this->getChannelNames();
  708. } elseif($this->isChannel($chanName)) {
  709. $tmp = $this->getChannel($chanName);
  710. $data = array($tmp[self::K_NAME]);
  711. }
  712. $out = array();
  713. foreach( $data as $chanName) {
  714. $channel = $this->getChannel($chanName);
  715. $out[$chanName] = array();
  716. foreach($channel[self::K_PACK] as $package=>$data) {
  717. $out[$chanName][$package] = array();
  718. foreach(array(self::K_VER, self::K_STATE) as $k) {
  719. $out[$chanName][$package][$k] = $data[$k];
  720. }
  721. }
  722. }
  723. return $out;
  724. }
  725. /**
  726. * Check if package conflicts with installed packages
  727. * Returns:
  728. * array with conflicts
  729. * false if no conflicts
  730. *
  731. * @param string $chanName
  732. * @param string $packageName
  733. * @param string $version
  734. * @return array|false
  735. */
  736. public function hasConflicts($chanName, $packageName, $version)
  737. {
  738. $conflicts = array();
  739. foreach($this->_data[self::K_CHAN] as $channel=>$data) {
  740. foreach($data[self::K_PACK] as $package) {
  741. if($channel != $chanName) {
  742. continue;
  743. }
  744. $deps = $package[self::K_PACK_DEPS];
  745. foreach($deps as $dep) {
  746. if($dep['name'] != $packageName) {
  747. continue;
  748. }
  749. if(!$this->versionInRange($version, $dep['min'], $dep['max'])) {
  750. //var_dump($version, $dep['min'], $dep['max']);
  751. $conflicts[] = $channel . "/". $package['name'] ." ". $package['version'];
  752. }
  753. }
  754. }
  755. }
  756. return count($conflicts) ? $conflicts : false;
  757. }
  758. }