PageRenderTime 44ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/all-in-one-wp-migration/lib/vendor/servmask/archiver/class-ai1wm-extractor.php

https://gitlab.com/haque.mdmanzurul/neophix
PHP | 296 lines | 157 code | 46 blank | 93 comment | 23 complexity | 5b5b61d33e1cde7e2f0d480bdec3f438 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright (C) 2014 ServMask Inc.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * ███████╗███████╗██████╗ ██╗ ██╗███╗ ███╗ █████╗ ███████╗██╗ ██╗
  19. * ██╔════╝██╔════╝██╔══██╗██║ ██║████╗ ████║██╔══██╗██╔════╝██║ ██╔╝
  20. * ███████╗█████╗ ██████╔╝██║ ██║██╔████╔██║███████║███████╗█████╔╝
  21. * ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██║╚██╔╝██║██╔══██║╚════██║██╔═██╗
  22. * ███████║███████╗██║ ██║ ╚████╔╝ ██║ ╚═╝ ██║██║ ██║███████║██║ ██╗
  23. * ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
  24. */
  25. class Ai1wm_Extractor extends Ai1wm_Archiver {
  26. /**
  27. * Overloaded constructor that opens the passed file for reading
  28. *
  29. * @param string $file File to use as archive
  30. */
  31. public function __construct( $file ) {
  32. // call parent, to initialize variables
  33. parent::__construct( $file );
  34. }
  35. /**
  36. * Extract files from archive to specified location
  37. *
  38. * @param string $location Location where the files should be extracted
  39. * @param int $seek Location in the file to start exporting data from
  40. */
  41. public function extract_files( $location, $seek = 0 ) {
  42. }
  43. /**
  44. * Get the number of files in an archive
  45. *
  46. * @return int Number of files found in the archive
  47. * @throws \Ai1wm_Not_Accesible_Exception
  48. * @throws \Ai1wm_Not_Readable_Exception
  49. */
  50. public function get_number_of_files() {
  51. // files counter
  52. $files_found = 0;
  53. while ( $block = $this->read_from_handle( $this->file_handle, 4377, $this->filename ) ) {
  54. // end block has been reached
  55. if ( $block === $this->eof ) {
  56. continue;
  57. }
  58. // get file data from the block
  59. $data = $this->get_data_from_block( $block );
  60. // we have a file, increment the counter
  61. $files_found++;
  62. // skip file content so we can move forward to the next file
  63. $this->set_file_pointer( $this->file_handle, $data['size'], $this->filename );
  64. }
  65. return $files_found;
  66. }
  67. public function extract_one_file_to( $location, $exclude = array() ) {
  68. if ( false === file_exists( $location ) ) {
  69. throw new Ai1wm_Not_Readable_Exception( sprintf( __( '%s doesn\'t exist', AI1WM_PLUGIN_NAME ), $location ) );
  70. }
  71. $block = $this->read_from_handle( $this->file_handle, 4377, $this->filename );
  72. if ( $block === $this->eof ) {
  73. // we reached end of file, set the pointer to the end of the file so that feof returns true
  74. @fseek( $this->file_handle, 1, SEEK_END );
  75. @fgetc( $this->file_handle );
  76. return;
  77. }
  78. // get file data from header block
  79. $data = $this->get_data_from_block( $block );
  80. // set filename
  81. if ( $data['path'] === '.' ) {
  82. $filename = $data['filename'];
  83. } else {
  84. $filename = $data['path'] . '/' . $data['filename'];
  85. }
  86. // should we skip this file?
  87. if ( in_array( $filename, $exclude ) ) {
  88. // we don't have a match, skip file content
  89. $this->set_file_pointer( $this->file_handle, $data['size'], $this->filename );
  90. return;
  91. }
  92. // we need to build the path for the file
  93. $path = str_replace( '/', DIRECTORY_SEPARATOR, $data['path'] );
  94. // append prepend extract location
  95. $path = $location . DIRECTORY_SEPARATOR . $path;
  96. // check if location doesn't exist, then create it
  97. if ( false === file_exists( $path ) ) {
  98. mkdir( $path, 0755, true );
  99. }
  100. try {
  101. $this->extract_to( $path . DIRECTORY_SEPARATOR . $data['filename'], $data );
  102. } catch ( Exception $e ) {
  103. // we don't have file permissions, skip file content
  104. $this->set_file_pointer( $this->file_handle, $data['size'], $this->filename );
  105. return;
  106. }
  107. }
  108. /**
  109. * Extract specific files from archive
  110. *
  111. * @param string $location Location where to extract files
  112. * @param array $files Files to extract
  113. */
  114. public function extract_by_files_array( $location, $files = array() ) {
  115. if ( false === file_exists( $location ) ) {
  116. throw new Ai1wm_Not_Readable_Exception( sprintf( __( '%s doesn\'t exist', AI1WM_PLUGIN_NAME ), $location ) );
  117. }
  118. // we read until we reached the end of the file, or the files we were looking for were found
  119. while (
  120. ($block = $this->read_from_handle( $this->file_handle, 4377, $this->filename )) &&
  121. ( count( $files ) > 0 )
  122. ) {
  123. // end block has been reached and we still have files to extract
  124. // that means the files don't exist in the archive
  125. if ( $block === $this->eof ) {
  126. // we reached end of file, set the pointer to the end of the file so that feof returns true
  127. @fseek( $this->file_handle, 1, SEEK_END );
  128. @fgetc( $this->file_handle );
  129. return;
  130. }
  131. $data = $this->get_data_from_block( $block );
  132. // set filename
  133. if ( $data['path'] === '.' ) {
  134. $filename = $data['filename'];
  135. } else {
  136. $filename = $data['path'] . '/' . $data['filename'];
  137. }
  138. // do we have a match?
  139. if ( in_array( $filename, $files ) ) {
  140. try {
  141. // we have a match, let's extract the file and remove it from the array
  142. $this->extract_to( $location . DIRECTORY_SEPARATOR . $data['filename'], $data );
  143. } catch ( Exception $e ) {
  144. // we don't have file permissions, skip file content
  145. $this->set_file_pointer( $this->file_handle, $data['size'], $this->filename );
  146. }
  147. // let's unset the file from the files array
  148. $key = array_search( $data['filename'], $files );
  149. unset( $files[$key] );
  150. } else {
  151. // we don't have a match, skip file content
  152. $this->set_file_pointer( $this->file_handle, $data['size'], $this->filename );
  153. }
  154. }
  155. }
  156. public function set_file_pointer( $handle = null, $offset = 0, $file = '' ) {
  157. // if null is used, we use the archive handle
  158. if ( is_null( $handle ) ) {
  159. $handle = $this->file_handle;
  160. }
  161. // if filename is empty, we use archive filename
  162. if ( empty( $file ) ) {
  163. $file = $this->filename;
  164. }
  165. // do we have offset to apply?
  166. if ( $offset > 0 ) {
  167. // set position to current location plus offset
  168. $result = fseek( $handle, $offset, SEEK_CUR );
  169. if ( -1 === $result ) {
  170. throw new Ai1wm_Not_Accesible_Exception(
  171. sprintf(
  172. __( 'Unable to seek to offset %d on %s', AI1WM_PLUGIN_NAME ),
  173. $offset,
  174. $file
  175. )
  176. );
  177. }
  178. }
  179. }
  180. private function extract_to( $file, $data, $overwrite = true ) {
  181. // local file handle
  182. $handle = null;
  183. // should the extract overwrite the file if it exists?
  184. if ( $overwrite ) {
  185. $handle = $this->open_file_for_overwriting( $file );
  186. } else {
  187. $handle = $this->open_file_for_writing( $file );
  188. }
  189. // is the filesize more than 0 bytes?
  190. while ( $data['size'] > 0 ) {
  191. // read the file in chunks of 512KB
  192. $length = $data['size'] > 512000 ? 512000 : $data['size'];
  193. // read the file in chunks of 512KB from archiver
  194. $content = $this->read_from_handle( $this->file_handle, $length, $this->filename );
  195. // remote the amount of bytes we read
  196. $data['size'] -= $length;
  197. // write file contents
  198. $this->write_to_handle( $handle, $content, $file );
  199. }
  200. // close the handle
  201. fclose( $handle );
  202. // let's apply last modified date
  203. $this->set_mtime_of_file( $file, $data['mtime'] );
  204. // all files should chmoded to 755
  205. $this->set_file_mode( $file, 0644 );
  206. }
  207. private function set_mtime_of_file( $file, $mtime ) {
  208. return @touch( $file, $mtime );
  209. }
  210. private function set_file_mode( $file, $mode = 0644 ) {
  211. return @chmod( $file, $mode );
  212. }
  213. private function get_data_from_block( $block ) {
  214. // prepare our array keys to unpack
  215. $format = array(
  216. $this->block_format[0] . 'filename/',
  217. $this->block_format[1] . 'size/',
  218. $this->block_format[2] . 'mtime/',
  219. $this->block_format[3] . 'path',
  220. );
  221. $format = implode( '', $format );
  222. $data = unpack( $format, $block );
  223. $data['filename'] = trim( $data['filename'] );
  224. $data['size'] = trim( $data['size'] );
  225. $data['mtime'] = trim( $data['mtime'] );
  226. $data['path'] = trim( $data['path'] );
  227. return $data;
  228. }
  229. /**
  230. * Check if file has reached end of file
  231. * Returns true if file has NOT reached eof, false otherwise
  232. *
  233. * @return bool
  234. */
  235. public function has_not_reached_eof() {
  236. return ! feof( $this->file_handle );
  237. }
  238. public function get_file_pointer() {
  239. $result = ftell( $this->file_handle );
  240. if ( false === $result ) {
  241. throw new Ai1wm_Not_Accesible_Exception(
  242. sprintf(
  243. __( 'Unable to get current pointer position of %s', AI1WM_PLUGIN_NAME ),
  244. $this->filename
  245. )
  246. );
  247. }
  248. return $result;
  249. }
  250. }