/** * Receives a new deployed services package to upgrade the running version * * @return void */ private function upgradeServices() { if (isset($this->request['package']) === false) { return; } $this->request['package'] = \Output::decodeWireObject($this->request['package']); /** * Confirm authenticity with origin before upgrading. */ $checksum = hash('sha1', $this->request['package']); if (\OriginRequest::validateDeployedPackage($checksum, $this->request['timestamp']) !== true) { \Output::render404(); } $upgradeDir = \BASE_DOCROOT_DIR . '/w_api_upgrade/'; if (mkdir($upgradeDir) !== true) { \Output::sendHeader($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error'); } file_put_contents($upgradeDir . 'w_api.zip', $this->request['package']); $zip = new \ZipArchive(); if ($zip->open($upgradeDir . 'w_api.zip', \ZipArchive::CHECKCONS) !== true) { /** * Bad archive -- do not upgrade */ $zip->close(); return; } if ($zip->extractTo($upgradeDir) !== true) { $zip->close(); return; } foreach (scandir($upgradeDir . '/w_api/') as $file) { if (strpos($file, '.php') !== false) { if (unlink(\BASE_SERVICES_DIR . $file) === false) { /** * Can't upgrade these services due to permissions errors, looks like */ $failure = true; break; } file_put_contents(\BASE_SERVICES_DIR . $file, file_get_contents($upgradeDir . '/w_api/' . $file)); unlink($upgradeDir . '/w_api/' . $file); } } \FileSystem::deleteTree($upgradeDir); $zip->close(); if (isset($failure) === true) { \Output::sendHeader($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error'); } }
/** * Unzips the content from a given object resource * * @param string $object * * @return bool */ public static function expandObject($object) { if (isset($object) === false) { return false; } /** * Create a fairly random place to drop this in -- it'll get removed at the end of execution anyway */ $path = \BASE_DOCROOT_DIR . md5(rand(0, 999)) . '.zip'; /** * Object should be "prop-up" ready, with a path that reflects where it should live on disk * from a relative path of the client webroot */ $object = file_put_contents($path, \Output::decodeWireObject($object)); $zip = new \ZipArchive(); if ($zip->open($path, \ZipArchive::CHECKCONS) !== true) { unlink($path); $zip->close(); return false; } /** * The @ symbol here is awful, but it's even more important that we don't throw a Warning on the extractTo if it fails * The early Warning shown causes any further rendering to get lost, because we've already started sending headers */ if (@$zip->extractTo(\BASE_DOCROOT_DIR) !== true) { /** * Something has gone really wrong -- send a 500. */ \Output::sendHeader($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error'); unlink($path); $zip->close(); throw new \Exception('Could not expand our origin object'); } unlink($path); $zip->close(); return true; }
/** * Handles a response from Origin, generally the last item in the lifecycle of a request * * @param mixed $response * * @return void */ private function handleOriginResponse($response) { /** * Origin didn't have the object */ if ($response === false) { \Output::render404(); } /** * We're good to go, start rendering */ \Output::sendHeader($_SERVER['SERVER_PROTOCOL'] . ' 200 OK'); /** * Origin had the object, and it's now stored on disk, render the stored object */ if ($response === true) { if (isset($_COOKIE['is_redirecting']) === true) { sleep(2); } \setcookie('is_redirecting', 1, time() + 5); \Output::sendHeader('Location: ' . $this->request['path']); $this->isRedirect = true; } if (is_object($response) === true) { /** * It's a streaming object, so we'll render it from here */ \Output::sendHeader($_SERVER['SERVER_PROTOCOL'] . ' 200 OK'); \Output::render(\Output::decodeWireObject($response->object)); } }