/** * Resolve any dependencies of the artifact represented in this vehicle. * * @param xPDOTransport &$transport A reference to the xPDOTransport in * which this vehicle is stored. * @param mixed &$object An object reference to resolve dependencies for. * Use this to make the artifact or other important data available to the * resolver scripts. * @param array $options Additional options for the resolution process. * @return boolean Indicates if the resolution was successful. */ public function resolve(&$transport, &$object, $options = array()) { $resolved = false; if (isset($this->payload['resolve'])) { while (list($rKey, $r) = each($this->payload['resolve'])) { $type = $r['type']; $body = $r['body']; $preExistingMode = xPDOTransport::PRESERVE_PREEXISTING; if (!empty($options[xPDOTransport::PREEXISTING_MODE])) { $preExistingMode = intval($options[xPDOTransport::PREEXISTING_MODE]); } switch ($type) { case 'file': if (isset($options[xPDOTransport::RESOLVE_FILES]) && !$options[xPDOTransport::RESOLVE_FILES]) { $resolved = true; continue; } if ($transport->xpdo->getDebug() === true) { $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Resolving transport files: " . print_r($this, true)); } $fileMeta = $transport->xpdo->fromJSON($body, true); $fileName = $fileMeta['name']; $fileSource = $transport->path . $fileMeta['source']; $fileTarget = eval($fileMeta['target']); $fileTargetPath = $fileTarget . $fileName; $preservedArchive = $transport->path . $transport->signature . '/' . $this->payload['class'] . '/' . $this->payload['signature'] . '.' . $rKey . '.preserved.zip'; $cacheManager = $transport->xpdo->getCacheManager(); switch ($options[xPDOTransport::PACKAGE_ACTION]) { case xPDOTransport::ACTION_UPGRADE: case xPDOTransport::ACTION_INSTALL: // if package is installing if ($cacheManager && file_exists($fileSource) && !empty($fileTarget)) { $copied = array(); if ($preExistingMode === xPDOTransport::PRESERVE_PREEXISTING && file_exists($fileTargetPath)) { $transport->xpdo->log(xPDO::LOG_LEVEL_INFO, "Attempting to preserve files at {$fileTargetPath} into archive {$preservedArchive}"); $preserved = xPDOTransport::_pack($transport->xpdo, $preservedArchive, $fileTarget, $fileName); } if (is_dir($fileSource)) { $copied = $cacheManager->copyTree($fileSource, $fileTarget, array_merge($options, array('copy_return_file_stat' => true))); } elseif (is_file($fileSource)) { $copied = $cacheManager->copyFile($fileSource, $fileTarget, array_merge($options, array('copy_return_file_stat' => true))); } if (empty($copied)) { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not copy {$fileSource} to {$fileTargetPath}"); } else { if ($preExistingMode === xPDOTransport::PRESERVE_PREEXISTING && is_array($copied)) { foreach ($copied as $copiedFile => $stat) { if (isset($stat['overwritten'])) { $transport->_preserved[$options['guid']]['files'][substr($copiedFile, strlen($fileTarget))] = $stat; } } } $resolved = true; } } else { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not copy {$fileSource} to {$fileTargetPath}"); } break; case xPDOTransport::ACTION_UNINSTALL: /* if package is uninstalling user can override whether or not files from resolver are removed however default action is to remove */ if (!isset($options[xPDOTransport::RESOLVE_FILES_REMOVE]) || $options[xPDOTransport::RESOLVE_FILES_REMOVE] !== false) { $path = $fileTarget . $fileName; $transport->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Removing files in file resolver: ' . $path); if ($cacheManager && file_exists($path)) { if (is_dir($path) && $cacheManager->deleteTree($path, array_merge(array('deleteTop' => true, 'skipDirs' => false, 'extensions' => array()), $options))) { $resolved = true; } elseif (is_file($path) && unlink($path)) { $resolved = true; } else { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not remove files from path: ' . $path); } } else { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not find files to remove.'); } } else { /* action was chosen not to remove, send log message and continue */ $transport->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Skipping removing of files according to vehicle attributes.'); $resolved = true; } if ($preExistingMode === xPDOTransport::RESTORE_PREEXISTING && file_exists($preservedArchive)) { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Attempting to restore files to {$fileTarget} from archive {$preservedArchive}"); $unpackedResult = xPDOTransport::_unpack($transport->xpdo, $preservedArchive, $fileTarget); if ($unpackedResult > 0) { $resolved = true; } else { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error unpacking preserved files from archive {$preservedArchive}"); } } break; } break; case 'php': if (isset($options[xPDOTransport::RESOLVE_PHP]) && !$options[xPDOTransport::RESOLVE_PHP]) { continue; } $fileMeta = $transport->xpdo->fromJSON($body, true); $fileName = $fileMeta['name']; $fileSource = $transport->path . $fileMeta['source']; if (!($resolved = (include $fileSource))) { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "xPDOVehicle resolver failed: type php ({$fileSource})"); } break; default: $transport->xpdo->log(xPDO::LOG_LEVEL_WARN, "xPDOVehicle does not support resolvers of type {$type}."); break; } } } else { $resolved = true; } return $resolved; }
/** * Uninstall files or folders represented by and stored in this vehicle. * * @access protected * @param xPDOTransport &$transport A reference the transport this vehicle is stored in. * @param array $options Optional attributes that can be applied to vehicle uninstall process. * @return boolean True if the files are uninstalled successfully. */ protected function _uninstallFiles(&$transport, $options) { $uninstalled = false; $vOptions = $this->get($transport, $options); if (isset($vOptions['object']) && isset($vOptions['object']['source']) && isset($vOptions['object']['target'])) { $object = $vOptions['object']; $fileName = $object['name']; $fileSource = $transport->path . $object['source']; $fileTarget = eval($object['target']); $preExistingMode = xPDOTransport::PRESERVE_PREEXISTING; if (isset($vOptions[xPDOTransport::PREEXISTING_MODE])) { $preExistingMode = (int) $vOptions[xPDOTransport::PREEXISTING_MODE]; } $cacheManager = $transport->xpdo->getCacheManager(); $path = $fileTarget . $fileName; $transport->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Uninstalling files from xPDOFileVehicle: ' . $path); if ($this->validate($transport, $object, $vOptions)) { if (!isset($vOptions[xPDOTransport::UNINSTALL_FILES]) || $vOptions[xPDOTransport::UNINSTALL_FILES] == true) { $transport->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Removing files from xPDOFileVehicle: ' . $path); if ($cacheManager && file_exists($path)) { if (is_dir($path) && $cacheManager->deleteTree($path, array_merge(array('deleteTop' => true, 'skipDirs' => false, 'extensions' => array()), $vOptions))) { $uninstalled = true; } elseif (is_file($path) && unlink($path)) { $uninstalled = true; } else { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not remove files from path: ' . $path); } } else { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not find files to remove at path: ' . $path); } } else { $transport->xpdo->log(xPDO::LOG_LEVEL_INFO, 'Skipping removal of files according to vehicle attributes.'); $uninstalled = true; } $preservedArchive = $transport->path . $transport->signature . '/' . $this->payload['class'] . '/' . $this->payload['signature'] . '.preserved.zip'; if ($preExistingMode === xPDOTransport::RESTORE_PREEXISTING && file_exists($preservedArchive)) { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Attempting to restore files to {$fileTarget} from archive {$preservedArchive}"); $unpackedResult = xPDOTransport::_unpack($transport->xpdo, $preservedArchive, $fileTarget); if ($unpackedResult > 0) { $uninstalled = true; } else { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, "Error unpacking preserved files from archive {$preservedArchive}"); } } if (!$this->resolve($transport, $object, $vOptions)) { $transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not resolve vehicle for object: ' . print_r($object, true)); if ($transport->xpdo->getDebug() === true) { $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not resolve vehicle: ' . print_r($vOptions, true)); } } } else { //$transport->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Could not validate vehicle for object: ' . print_r($object, true)); if ($transport->xpdo->getDebug() === true) { $transport->xpdo->log(xPDO::LOG_LEVEL_DEBUG, 'Could not validate vehicle: ' . print_r($vOptions, true)); } } } return $uninstalled; }
/** * Unpack the package to prepare for installation and return a manifest. * * @param xPDO &$xpdo A reference to an xPDO instance. * @param string $from Filename of the archive containing the transport package. * @param string $to The root path where the contents of the archive should be extracted. This * path must be writable by the user executing the PHP process on the server. * @param integer $state The current state of the package, i.e. packed or unpacked. * @return array The manifest which is included after successful extraction. */ public static function unpack(&$xpdo, $from, $to, $state = xPDOTransport::STATE_PACKED) { $manifest = null; if ($state !== xPDOTransport::STATE_UNPACKED) { $resources = xPDOTransport::_unpack($xpdo, $from, $to); } else { $resources = true; } if ($resources) { $manifestFilename = $to . basename($from, '.transport.zip') . '/manifest.php'; if (file_exists($manifestFilename)) { $manifest = @(include $manifestFilename); } else { $xpdo->log(xPDO::LOG_LEVEL_ERROR, "Could not find package manifest at {$manifestFilename}"); } } return $manifest; }