/application/libraries/Engine/Package/Archive.php

https://github.com/grandison/budo16 · PHP · 194 lines · 138 code · 21 blank · 35 comment · 45 complexity · 89fd239e285d8b3b6eeca5b3d8d18f17 MD5 · raw file

  1. <?php
  2. /**
  3. * SocialEngine
  4. *
  5. * @category Engine
  6. * @package Engine_Package
  7. * @copyright Copyright 2006-2010 Webligo Developments
  8. * @license http://www.socialengine.net/license/
  9. * @version $Id: Archive.php 7244 2010-09-01 01:49:53Z john $
  10. * @author John Boehr <j@webligo.com>
  11. */
  12. /**
  13. * @category Engine
  14. * @package Engine_Filter
  15. * @copyright Copyright 2006-2010 Webligo Developments
  16. * @license http://www.socialengine.net/license/
  17. * @author John Boehr <j@webligo.com>
  18. */
  19. class Engine_Package_Archive
  20. {
  21. static public function inflate($file, $outputPath)
  22. {
  23. // Sanity
  24. if( !file_exists($file) || !is_file($file) || strtolower(pathinfo($file, PATHINFO_EXTENSION)) != 'tar' ) {
  25. throw new Engine_Package_Exception('File does not exist or is not a tar file');
  26. }
  27. if( !file_exists($outputPath) || !is_dir($outputPath) || !is_writeable($outputPath) ) {
  28. throw new Engine_Package_Exception('Output path does not exist, is not a directory, or is not writeable');
  29. }
  30. self::_loadArchiveClass();
  31. // Make other paths
  32. $outputSubPath = substr(basename($file), 0, strrpos(basename($file), '.'));
  33. $outputFullPath = rtrim($outputPath, '/\\') . DIRECTORY_SEPARATOR . $outputSubPath;
  34. // If output path already exists, remove
  35. if( file_exists($outputFullPath) ) {
  36. self::_rmdirRecursive($outputFullPath, true);
  37. }
  38. // Try to make full output path
  39. if( !is_dir($outputFullPath) ) {
  40. if( !mkdir($outputFullPath, 0777, true) ) {
  41. throw new Engine_Package_Exception('Unable to create output folder');
  42. }
  43. }
  44. // Extract
  45. $archive = new Archive_Tar($file);
  46. $rval = $archive->extract($outputFullPath);
  47. // Throw error if failed
  48. if( $archive->isError($rval) ) {
  49. throw new Engine_Package_Exception('Error in archive: ' . $rval->getMessage());
  50. }
  51. return $outputFullPath;
  52. }
  53. static public function deflate(Engine_Package_Manifest $package, $outputPath)
  54. {
  55. // Sanity
  56. if( !file_exists($outputPath) || !is_dir($outputPath) || !is_writeable($outputPath) ) {
  57. throw new Engine_Package_Exception('Output path does not exist, is not a directory, or is not writeable');
  58. }
  59. if( !is_dir($package->getBasePath()) ) {
  60. throw new Engine_Package_Exception('Missing package base path');
  61. }
  62. self::_loadArchiveClass();
  63. // Make filenames and paths
  64. $basePath = $package->getBasePath();
  65. $archiveFile = $package->getKey() . '.tar';
  66. $archiveFullPath = $outputPath . DIRECTORY_SEPARATOR . $archiveFile;
  67. if( file_exists($archiveFullPath) && !unlink($archiveFullPath) ) {
  68. throw new Engine_Package_Exception('Target archive already exists and unable to remove');
  69. }
  70. // Start packing
  71. $archive = new Archive_Tar($archiveFullPath);
  72. $archive->setIgnoreList(array('CVS', '.svn'));
  73. // Add all directories, files, and subpackages
  74. $package->addToArchive($archive);
  75. return $archiveFullPath;
  76. }
  77. static public function readPackageFile($file)
  78. {
  79. // Sanity
  80. if( !file_exists($file) || !is_file($file) || strtolower(pathinfo($file, PATHINFO_EXTENSION)) != 'tar' ) {
  81. throw new Engine_Package_Exception('File does not exist or is not a tar file');
  82. }
  83. self::_loadArchiveClass();
  84. // Create archive object
  85. $archive = new Archive_Tar($file);
  86. // List files
  87. $fileList = $archive->listContent();
  88. if( empty($fileList) ) {
  89. throw new Engine_Package_Exception('Unable to open archive');
  90. }
  91. // Check for root package file
  92. $rootPackageFile = null;
  93. foreach( $fileList as $arFile ) {
  94. if( $arFile['filename'] == 'package.json' ) {
  95. $rootPackageFile = $arFile['filename'];
  96. break;
  97. }
  98. }
  99. if( null === $rootPackageFile ) {
  100. throw new Engine_Package_Exception('Root package file not found.');
  101. }
  102. // Start building package stuff
  103. $packageFileObject = new Engine_Package_Manifest();
  104. $packageFileObject->fromString($archive->extractInString($rootPackageFile), 'json');
  105. return $packageFileObject;
  106. }
  107. static protected function _loadArchiveClass()
  108. {
  109. include_once 'Archive/Tar.php';
  110. if( !class_exists('Archive_Tar', false) ) {
  111. throw new Engine_Package_Exception('Unable to load Archive_Tar class');
  112. }
  113. }
  114. static protected function _addPackageToArchive(Engine_Package_Manifest $package, Archive_Tar $archive, $basePath)
  115. {
  116. $rval = null;
  117. foreach( $package->getStructure() as $name => $contents ) {
  118. if( !($contents instanceof Engine_Package_Manifest_Entity_Abstract) ) {
  119. continue;
  120. }
  121. switch( $contents->getType() ) {
  122. case 'package':
  123. $subPackageObject = new Engine_Package_Manifest($basePath . DIRECTORY_SEPARATOR . $contents['path'] . DIRECTORY_SEPARATOR . $contents['packageFile']);
  124. $subPackageObject->setBasePath($basePath);
  125. self::_addPackageToArchive($subPackageObject, $archive, $basePath);
  126. break;
  127. case 'directory':
  128. // Add directory
  129. $rval = $archive->addModify($basePath . DIRECTORY_SEPARATOR . $contents['path'], null, $basePath);
  130. if( $archive->isError($rval) ) {
  131. throw new Engine_Package_Exception(sprintf('Unable to add path "%s" to archive', $contents['path']));
  132. }
  133. break;
  134. case 'file':
  135. // Add file
  136. $rval = $archive->addModify($basePath . DIRECTORY_SEPARATOR . $contents['path'], null, $basePath);
  137. if( $archive->isError($rval) ) {
  138. throw new Engine_Package_Exception(sprintf('Unable to add path "%s" to archive', $contents['path']));
  139. }
  140. break;
  141. default:
  142. throw new Engine_Package_Exception('unknown contents type');
  143. break;
  144. }
  145. }
  146. // Throw error if failed
  147. if( $archive->isError($rval) ) {
  148. throw new Engine_Package_Exception('Error in archive: ' . $rval->getMessage());
  149. }
  150. }
  151. static protected function _rmdirRecursive($path, $includeSelf = false)
  152. {
  153. $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::KEY_AS_PATHNAME), RecursiveIteratorIterator::CHILD_FIRST);
  154. foreach( $it as $key => $child ) {
  155. if( $child->getFilename() == '.' || $child->getFilename() == '..' || $child->getFilename() == '.svn' ) {
  156. continue;
  157. } else if( $child->isDir() ) {
  158. if( !rmdir($key) ) {
  159. throw new Engine_Package_Exception(sprintf('Unable to remove directory: %s', $key));
  160. }
  161. } else if( $child->isFile() ) {
  162. if( !unlink($key) ) {
  163. throw new Engine_Package_Exception(sprintf('Unable to remove file: %s', $key));
  164. }
  165. }
  166. }
  167. if( $includeSelf ) {
  168. if( is_dir($path) && !rmdir($path) ) {
  169. throw new Engine_Package_Exception(sprintf('Unable to remove directory: %s', $path));
  170. }
  171. }
  172. }
  173. }