TYPO3 CMS  TYPO3_6-2
CoreUpdateService.php
Go to the documentation of this file.
1 <?php
3 
23 
35 
40  protected $objectManager;
41 
47 
51  protected $messages = array();
52 
59 
66 
72  protected $downloadBaseUri;
73 
77  public function initializeObject() {
78  $this->setDownloadTargetPath(PATH_site . 'typo3temp/core-update/');
79  $this->symlinkToCoreFiles = $this->discoverCurrentCoreLocation();
80  $this->downloadBaseUri = $this->coreVersionService->getDownloadBaseUri();
81  }
82 
88  public function isCoreUpdateEnabled() {
89  $coreUpdateDisabled = getenv('TYPO3_DISABLE_CORE_UPDATER') ?: (getenv('REDIRECT_TYPO3_DISABLE_CORE_UPDATER') ?: FALSE);
90  return !$coreUpdateDisabled;
91  }
92 
98  protected function discoverCurrentCoreLocation() {
99  return PATH_site . 'typo3_src';
100  }
101 
109  if (!is_dir($downloadTargetPath)) {
111  }
112  $this->downloadTargetPath = $downloadTargetPath;
113  }
114 
120  public function getMessages() {
121  return $this->messages;
122  }
123 
129  public function updateVersionMatrix() {
130  $success = TRUE;
131  try {
132  $this->coreVersionService->updateVersionMatrix();
133  } catch (RemoteFetchException $e) {
134  $success = FALSE;
136  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
137  $message->setTitle('Version matrix could not be fetched from get.typo3.org');
138  $message->setMessage(
139  'Current version specification could not be fetched from http://get.typo3.org/json.'
140  . ' This is probably a network issue, please fix it.'
141  );
142  $this->messages = array($message);
143  }
144  return $success;
145  }
146 
154  public function checkPreConditions($version) {
155  $success = TRUE;
156  $messages = array();
157 
159  $statusUtility = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\StatusUtility');
160 
161  // Folder structure test: Update can be done only if folder structure returns no errors
163  $folderStructureFacade = $this->objectManager->get('TYPO3\\CMS\\Install\\FolderStructure\\DefaultFactory')->getStructure();
164  $folderStructureErrors = $statusUtility->filterBySeverity($folderStructureFacade->getStatus(), 'error');
165  $folderStructureWarnings = $statusUtility->filterBySeverity($folderStructureFacade->getStatus(), 'warning');
166  if (count($folderStructureErrors) > 0 || count($folderStructureWarnings) > 0) {
167  $success = FALSE;
169  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
170  $message->setTitle('Automatic TYPO3 CMS core update not possible: Folder structure has errors or warnings');
171  $message->setMessage(
172  'To perform an update, the folder structure of this TYPO3 CMS instance must'
173  . ' stick to the conventions, or the update process could lead to unexpected'
174  . ' results and may be hazardous to your system'
175  );
176  $messages[] = $message;
177  }
178 
179  // No core update on windows
180  if (TYPO3_OS === 'WIN') {
181  $success = FALSE;
183  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
184  $message->setTitle('Automatic TYPO3 CMS core update not possible: Update not supported on Windows OS');
185  $messages[] = $message;
186  }
187 
188  if ($success) {
189  // Explicit write check to document root
190  $file = PATH_site . uniqid('install-core-update-test-', TRUE);
191  $result = @touch($file);
192  if (!$result) {
193  $success = FALSE;
195  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
196  $message->setTitle('Automatic TYPO3 CMS core update not possible: No write access to document root');
197  $message->setMessage('Could not write a file in path "' . PATH_site . '"!');
198  $messages[] = $message;
199  } else {
200  unlink($file);
201  }
202 
203  if (!$this->checkCoreFilesAvailable($version)) {
204  // Explicit write check to upper directory of current core location
205  $coreLocation = @realPath($this->symlinkToCoreFiles . '/../');
206  $file = $coreLocation . '/' . uniqid('install-core-update-test-', TRUE);
207  $result = @touch($file);
208  if (!$result) {
209  $success = FALSE;
211  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
212  $message->setTitle('Automatic TYPO3 CMS core update not possible: No write access to TYPO3 CMS core location');
213  $message->setMessage(
214  'New TYPO3 CMS core should be installed in "' . $coreLocation . '", but this directory is not writable!'
215  );
216  $messages[] = $message;
217  } else {
218  unlink($file);
219  }
220  }
221  }
222 
223  if ($success && !$this->coreVersionService->isInstalledVersionAReleasedVersion()) {
224  $success = FALSE;
226  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
227  $message->setTitle('Automatic TYPO3 CMS core update not possible: You are running a development version of TYPO3');
228  $message->setMessage(
229  'Your current version is specified as ' . $this->coreVersionService->getInstalledVersion() . '.'
230  . ' This is a development version and can not be updated automatically. If this is a "git"'
231  . ' checkout, please update using git directly.'
232  );
233  $messages[] = $message;
234  }
235 
236  $this->messages = $messages;
237  return $success;
238  }
239 
246  public function downloadVersion($version) {
247  $messages = array();
248  $success = TRUE;
249 
250  if ($this->checkCoreFilesAvailable($version)) {
252  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\NoticeStatus');
253  $message->setTitle('Skipped download of TYPO3 CMS core. A core source directory already exists in destination path. Using this instead.');
254  $messages[] = $message;
255  } else {
256  $downloadUri = $this->downloadBaseUri . $version;
257  $fileLocation = $this->getDownloadTarGzTargetPath($version);
258 
259  if (@file_exists($fileLocation)) {
260  $success = FALSE;
262  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
263  $message->setTitle('TYPO3 CMS core download exists in download location: ' . PathUtility::stripPathSitePrefix($this->downloadTargetPath));
264  $messages[] = $message;
265  } else {
266  $fileContent = GeneralUtility::getUrl($downloadUri);
267  if (!$fileContent) {
268  $success = FALSE;
270  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
271  $message->setTitle('Download not successful');
272  $messages[] = $message;
273  } else {
274  $fileStoreResult = file_put_contents($fileLocation, $fileContent);
275  if (!$fileStoreResult) {
276  $success = FALSE;
278  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
279  $message->setTitle('Unable to store download content');
280  $messages[] = $message;
281  } else {
282  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
283  $message->setTitle('TYPO3 CMS core download finished');
284  $messages[] = $message;
285  }
286  }
287  }
288  }
289  $this->messages = $messages;
290  return $success;
291  }
292 
299  public function verifyFileChecksum($version) {
300  $messages = array();
301  $success = TRUE;
302 
303  if ($this->checkCoreFilesAvailable($version)) {
305  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\WarningStatus');
306  $message->setTitle('Verifying existing TYPO3 CMS core checksum is not possible');
307  $messages[] = $message;
308  } else {
309  $fileLocation = $this->getDownloadTarGzTargetPath($version);
310  $expectedChecksum = $this->coreVersionService->getTarGzSha1OfVersion($version);
311 
312  if (!file_exists($fileLocation)) {
313  $success = FALSE;
315  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
316  $message->setTitle('Downloaded TYPO3 CMS core not found');
317  $messages[] = $message;
318  } else {
319  $actualChecksum = sha1_file($fileLocation);
320  if ($actualChecksum !== $expectedChecksum) {
321  $success = FALSE;
323  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
324  $message->setTitle('New TYPO3 CMS core checksum mismatch');
325  $message->setMessage(
326  'The official TYPO3 CMS version system on https://get.typo3.org expects a sha1 checksum of '
327  . $expectedChecksum . ' from the content of the downloaded new TYPO3 CMS core version ' . $version . '.'
328  . ' The actual checksum is ' . $actualChecksum . '. The update is stopped. This may be a'
329  . ' failed download, an attack, or an issue with the typo3.org infrastructure.'
330  );
331  $messages[] = $message;
332  } else {
333  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
334  $message->setTitle('Checksum verified');
335  $messages[] = $message;
336  }
337  }
338  }
339  $this->messages = $messages;
340  return $success;
341  }
342 
349  public function unpackVersion($version) {
350  $messages = array();
351  $success = TRUE;
352 
353  if ($this->checkCoreFilesAvailable($version)) {
355  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\NoticeStatus');
356  $message->setTitle('Unpacking TYPO3 CMS core files skipped');
357  $messages[] = $message;
358  } else {
359  $fileLocation = $this->downloadTargetPath . $version . '.tar.gz';
360 
361  if (!@is_file($fileLocation)) {
362  $success = FALSE;
364  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
365  $message->setTitle('Downloaded TYPO3 CMS core not found');
366  $messages[] = $message;
367  } elseif (@file_exists($this->downloadTargetPath . 'typo3_src-' . $version)) {
368  $success = FALSE;
370  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
371  $message->setTitle('Unpacked TYPO3 CMS core exists in download location: ' . PathUtility::stripPathSitePrefix($this->downloadTargetPath));
372  $messages[] = $message;
373  } else {
374  $unpackCommand = 'tar xf ' . escapeshellarg($fileLocation) . ' -C ' . escapeshellarg($this->downloadTargetPath) . ' 2>&1';
375  exec($unpackCommand, $output, $errorCode);
376  if ($errorCode) {
377  $success = FALSE;
379  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
380  $message->setTitle('Unpacking TYPO3 CMS core not successful');
381  $messages[] = $message;
382  } else {
383  $removePackedFileResult = unlink($fileLocation);
384  if (!$removePackedFileResult) {
385  $success = FALSE;
387  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
388  $message->setTitle('Removing packed TYPO3 CMS core not successful');
389  $messages[] = $message;
390  } else {
391  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
392  $message->setTitle('Unpacking TYPO3 CMS core successful');
393  $messages[] = $message;
394  }
395  }
396  }
397  }
398  $this->messages = $messages;
399  return $success;
400  }
401 
408  public function moveVersion($version) {
409  $messages = array();
410  $success = TRUE;
411 
412  if ($this->checkCoreFilesAvailable($version)) {
414  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\NoticeStatus');
415  $message->setTitle('Moving TYPO3 CMS core files skipped');
416  $messages[] = $message;
417  } else {
418  $downloadedCoreLocation = $this->downloadTargetPath . 'typo3_src-' . $version;
419  $newCoreLocation = @realPath($this->symlinkToCoreFiles . '/../') . '/typo3_src-' . $version;
420 
421  if (!@is_dir($downloadedCoreLocation)) {
422  $success = FALSE;
424  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
425  $message->setTitle('Unpacked TYPO3 CMS core not found');
426  $messages[] = $message;
427  } else {
428  $moveResult = rename($downloadedCoreLocation, $newCoreLocation);
429  if (!$moveResult) {
430  $success = FALSE;
432  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
433  $message->setTitle('Moving TYPO3 CMS core to ' . $newCoreLocation . ' failed');
434  $messages[] = $message;
435  } else {
436  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\OkStatus');
437  $message->setTitle('Moved TYPO3 CMS core to final location');
438  $messages[] = $message;
439  }
440  }
441  }
442 
443  $this->messages = $messages;
444  return $success;
445  }
446 
453  public function activateVersion($version) {
454  $newCoreLocation = @realPath($this->symlinkToCoreFiles . '/../') . '/typo3_src-' . $version;
455 
456  $messages = array();
457  $success = TRUE;
458 
459  if (!is_dir($newCoreLocation)) {
460  $success = FALSE;
462  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
463  $message->setTitle('New TYPO3 CMS core not found');
464  $messages[] = $message;
465  } elseif (!is_link($this->symlinkToCoreFiles)) {
466  $success = FALSE;
468  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
469  $message->setTitle('TYPO3 CMS core source directory (typo3_src) is not a link');
470  $messages[] = $message;
471  } else {
472  $isCurrentCoreSymlinkAbsolute = PathUtility::isAbsolutePath(readlink($this->symlinkToCoreFiles));
473  $unlinkResult = unlink($this->symlinkToCoreFiles);
474  if (!$unlinkResult) {
475  $success = FALSE;
477  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
478  $message->setTitle('Removing old symlink failed');
479  $messages[] = $message;
480  } else {
481  if (!$isCurrentCoreSymlinkAbsolute) {
482  $newCoreLocation = $this->getRelativePath($newCoreLocation);
483  }
484  $symlinkResult = symlink($newCoreLocation, $this->symlinkToCoreFiles);
485  if ($symlinkResult) {
487  } else {
488  $success = FALSE;
490  $message = $this->objectManager->get('TYPO3\\CMS\\Install\\Status\\ErrorStatus');
491  $message->setTitle('Linking new TYPO3 CMS core failed');
492  $messages[] = $message;
493  }
494  }
495  }
496 
497  $this->messages = $messages;
498  return $success;
499  }
500 
507  protected function getDownloadTarGzTargetPath($version) {
508  return $this->downloadTargetPath . $version . '.tar.gz';
509  }
510 
517  protected function getRelativePath($absolutePath) {
518  $sourcePath = explode(DIRECTORY_SEPARATOR, rtrim(PATH_site, DIRECTORY_SEPARATOR));
519  $targetPath = explode(DIRECTORY_SEPARATOR, rtrim($absolutePath, DIRECTORY_SEPARATOR));
520  while (count($sourcePath) && count($targetPath) && $sourcePath[0] === $targetPath[0]) {
521  array_shift($sourcePath);
522  array_shift($targetPath);
523  }
524  return str_pad('', count($sourcePath) * 3, '..' . DIRECTORY_SEPARATOR) . implode(DIRECTORY_SEPARATOR, $targetPath);
525  }
526 
534  protected function checkCoreFilesAvailable($version) {
535  $newCoreLocation = @realPath($this->symlinkToCoreFiles . '/../') . '/typo3_src-' . $version;
536  return @is_dir($newCoreLocation);
537  }
538 
539 }
static mkdir_deep($directory, $deepDirectory='')
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
static getUrl($url, $includeHeader=0, $requestHeaders=FALSE, &$report=NULL)