public function downloadTheme($name, $url, $signature) { $model = Model::instance(); //download theme $net = new \Ip\Internal\NetHelper(); $themeTempFilename = $net->downloadFile($url, ipFile('file/secure/tmp/'), $name . '.zip'); if (!$themeTempFilename) { throw new \Ip\Exception('Theme file download failed.'); } $archivePath = ipFile('file/secure/tmp/' . $themeTempFilename); //check signature $fileMd5 = md5_file($archivePath); $rsa = new \Crypt_RSA(); $rsa->loadKey($this->publicKey); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $verified = $rsa->verify($fileMd5, base64_decode($signature)); if (!$verified) { throw new \Ip\Exception('Theme signature verification failed.'); } //extract $helper = Helper::instance(); $secureTmpDir = ipFile('file/secure/tmp/'); $tmpExtractedDir = \Ip\Internal\File\Functions::genUnoccupiedName($name, $secureTmpDir); \Ip\Internal\Helper\Zip::extract($secureTmpDir . $themeTempFilename, $secureTmpDir . $tmpExtractedDir); unlink($archivePath); //install $extractedDir = $helper->getFirstDir($secureTmpDir . $tmpExtractedDir); $installDir = $model->getThemeInstallDir(); $newThemeDir = \Ip\Internal\File\Functions::genUnoccupiedName($name, $installDir); rename($secureTmpDir . $tmpExtractedDir . '/' . $extractedDir, $installDir . $newThemeDir); }
public function downloadPlugin($name, $url, $signature) { if (is_dir(ipFile("Plugin/{$name}/"))) { Service::deactivatePlugin($name); Helper::removeDir(ipFile("Plugin/{$name}/")); } //download plugin $net = new \Ip\Internal\NetHelper(); $pluginTempFilename = $net->downloadFile($url, ipFile('file/secure/tmp/'), $name . '.zip'); if (!$pluginTempFilename) { throw new \Ip\Exception('Plugin file download failed.'); } $archivePath = ipFile('file/secure/tmp/' . $pluginTempFilename); //check signature $fileMd5 = md5_file($archivePath); $rsa = new \Crypt_RSA(); $rsa->loadKey($this->publicKey); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $verified = $rsa->verify($fileMd5, base64_decode($signature)); if (!$verified) { throw new \Ip\Exception('Plugin signature verification failed.'); } //extract $secureTmpDir = ipFile('file/secure/tmp/'); $tmpExtractedDir = \Ip\Internal\File\Functions::genUnoccupiedName($name, $secureTmpDir); \Ip\Internal\Helper\Zip::extract($secureTmpDir . $pluginTempFilename, $secureTmpDir . $tmpExtractedDir); unlink($archivePath); //install $extractedDir = $this->getFirstDir($secureTmpDir . $tmpExtractedDir); $installDir = Model::pluginInstallDir(); $newPluginDir = \Ip\Internal\File\Functions::genUnoccupiedName($name, $installDir); rename($secureTmpDir . $tmpExtractedDir . '/' . $extractedDir, $installDir . $newPluginDir); Service::activatePlugin($name); }
public static function download() { $requestFile = ipFile('') . ipRequest()->getRelativePath(); $fileDir = ipFile('file/'); if (mb_strpos($requestFile, $fileDir) !== 0) { return null; } $file = mb_substr($requestFile, mb_strlen($fileDir)); $file = urldecode($file); if (empty($file)) { throw new \Ip\Exception('Required parameter is missing'); } $absoluteSource = realpath(ipFile('file/' . $file)); if (!$absoluteSource || !is_file($absoluteSource)) { throw new \Ip\Exception\Repository\Transform("File doesn't exist", array('filename' => $absoluteSource)); } if (strpos($absoluteSource, realpath(ipFile('file/'))) !== 0 || strpos($absoluteSource, realpath(ipFile('file/secure'))) === 0) { throw new \Exception("Requested file (" . $file . ") is outside of public dir"); } $mime = \Ip\Internal\File\Functions::getMimeType($absoluteSource); $fsize = filesize($absoluteSource); // set headers header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); header("Cache-Control: public"); header('Content-type: ' . $mime); header("Content-Transfer-Encoding: binary"); header("Content-Length: " . $fsize); // download // @readfile($file_path); $file = @fopen($absoluteSource, "rb"); if ($file) { while (!feof($file)) { print fread($file, 1024 * 8); flush(); if (connection_status() != 0) { @fclose($file); die; } } @fclose($file); } //TODO provide method to stop any output by ImpressPages ipDb()->disconnect(); exit; }
public function downloadFile($url, $destinationDir, $desiredFilename, $forceFilename = false) { if (!$forceFilename) { $desiredFilename = \Ip\Internal\File\Functions::genUnoccupiedName($desiredFilename, $destinationDir); } if (!function_exists('curl_init')) { throw new \Exception('CURL is not installed. Cannot download file from URL.'); } $ch = curl_init(); $fh = fopen($destinationDir . $desiredFilename, 'w'); $options = array(CURLOPT_FILE => $fh, CURLOPT_TIMEOUT => 1800, CURLOPT_URL => $url); curl_setopt_array($ch, $options); if (curl_exec($ch)) { return $desiredFilename; } else { $this->lastError = curl_error($ch); return false; } }
/** * Adds email to the queue * * Even if there is a big amount of emails, there is always reserved 20% of traffic for immediate emails. * Such emails are: registration cofirmation, contact form data and other. * Newsletters, greetings always can wait a litle. So they are not immediate and will not be send if is less than 20% of traffic left. * * @param string $from email address from whish an email should be send * @param $fromName * @param string $to email address where an email should be send * @param $toName * @param $subject * @param string $email email html text * @param bool $immediate indicate hurry of an email. * @param bool $html true if email message should be send as html * @param array $files files that should be attached to the email. Files should be accessible for php at this moment. They will be cached until send time. * @internal param $string @fromName * @internal param $string @toName */ function addEmail($from, $fromName, $to, $toName, $subject, $email, $immediate, $html, $files = null) { $cached_files = array(); $cached_fileNames = array(); $cached_fileMimeTypes = array(); if ($files) { if (is_string($files)) { $files = array($files); } foreach ($files as $fileSetting) { $file = array(); if (is_array($fileSetting)) { $file['real_name'] = $fileSetting[0]; $file['required_name'] = basename($fileSetting[1]); } else { $file['real_name'] = $fileSetting; $file['required_name'] = $fileSetting; } $new_name = 'contact_form_' . rand(); $new_name = \Ip\Internal\File\Functions::genUnoccupiedName($new_name, ipFile('file/tmp/')); if (copy($file['real_name'], ipFile('file/tmp/' . $new_name))) { $cached_files[] = ipFile('file/tmp/' . $new_name); $cached_fileNames[] = $file['required_name']; $tmpMimeType = \Ip\Internal\File\Functions::getMimeType($file['real_name']); if ($tmpMimeType == null) { $tmpMimeType = 'Application/octet-stream'; } $cached_fileMimeTypes[] = $tmpMimeType; } else { trigger_error('File caching failed'); } } } $cachedFilesStr = implode("\n", $cached_files); $cachedFileNamesStr = implode("\n", $cached_fileNames); $cachedFileMimeTypesStr = implode("\n", $cached_fileMimeTypes); $email = str_replace('src="' . ipConfig()->baseUrl(), 'src="', $email); Db::addEmail($from, $fromName, $to, $toName, $subject, $email, $immediate, $html, $cachedFilesStr, $cachedFileNamesStr, $cachedFileMimeTypesStr); }
/** * Add file to the repository. * @param string $file absolute path to file in tmp directory * @param null|string $desiredName desired file name in repository. * @return string relative file name in repository * @throws \Ip\Exception */ public function addFile($file, $desiredName) { if (!is_file($file)) { throw new \Ip\Exception("File doesn't exist"); } if (strpos(realpath($file), realpath(ipFile('file/repository/'))) === 0) { throw new \Ip\Exception("Requested file (" . $file . ") is already in the repository"); } $destination = ipFile('file/repository/'); if ($desiredName === null) { $desiredName = basename($file); //to avoid any tricks with relative paths, etc. } $newName = \Ip\Internal\File\Functions::genUnoccupiedName($desiredName, $destination); copy($file, $destination . $newName); return $newName; }
/** * @param string $url * @return string */ protected function downloadFile($url, $title) { //download image to TMP dir and get $resultFilename $net = new \Ip\Internal\NetHelper(); $tmpFilename = $net->downloadFile($url, ipFile('file/tmp/'), 'bigstock_' . time()); if (!$tmpFilename) { return null; } //find out file mime type to know required extension try { $mime = \Ip\Internal\File\Functions::getMimeType(ipFile('file/tmp/' . $tmpFilename)); switch ($mime) { case 'image/png': $ext = '.jpg'; break; case 'image/gif': $ext = '.gif'; break; case 'image/bmp': $ext = '.bmp'; break; case 'image/pjpeg': case 'image/jpeg': default: $ext = '.jpg'; break; } } catch (\Ip\PhpException $e) { $ext = '.jpg'; } //get real nice new file name $title = \Ip\Internal\File\Functions::cleanupFileName($title); $words = explode(' ', $title); $cleanTitle = ''; foreach ($words as $word) { //limit file name to 30 symbols if (strlen($cleanTitle . '_' . $word) > 30) { break; } if ($cleanTitle != '') { $cleanTitle .= '_'; } $cleanTitle .= $word; } if ($cleanTitle == '') { $cleanTitle = 'file'; } $niceFileName = $cleanTitle . $ext; $destinationDir = ipFile('file/repository/'); $destinationFileName = \Ip\Internal\File\Functions::genUnoccupiedName($niceFileName, $destinationDir); copy(ipFile('file/tmp/' . $tmpFilename), $destinationDir . $destinationFileName); unlink(ipFile('file/tmp/' . $tmpFilename)); $browserModel = \Ip\Internal\Repository\BrowserModel::instance(); $file = $browserModel->getFile($destinationFileName); return $file; }
private function createReflectionRecord($source, $options, $desiredName) { $absoluteSource = realpath(ipFile('file/repository/' . $source)); if (!$absoluteSource || !is_file($absoluteSource)) { throw new \Ip\Exception\Repository\Transform("File doesn't exist", array('filename' => $absoluteSource)); } if (strpos($absoluteSource, realpath(ipFile('file/repository/'))) !== 0) { throw new \Exception("Requested file (" . $source . ") is outside repository dir"); } //if desired name ends with .jpg, .gif, etc., remove extension $desiredPathInfo = pathinfo($desiredName); if (!empty($desiredPathInfo['filename']) && isset($desiredPathInfo['extension']) && strlen($desiredPathInfo['extension']) <= 4) { $desiredName = $desiredPathInfo['filename']; } //update destination file extension $pathInfo = pathinfo($absoluteSource); if (isset($pathInfo['extension'])) { $ext = $pathInfo['extension']; } else { $ext = ''; } $ext = ipFilter('ipReflectionExtension', $ext, array('source' => $absoluteSource, 'options' => $options)); if ($desiredName == '') { $pathInfo = pathinfo($absoluteSource); $desiredName = $pathInfo['filename']; } if ($ext != '') { $desiredName = $desiredName . '.' . $ext; } $desiredName = \Ip\Internal\File\Functions::cleanupFileName($desiredName); //remove double dots if file name. For security reasons. $relativeDestinationPath = date('Y/m/d/'); $relativeDestinationPath = ipFilter('ipRepositoryNewReflectionFileName', $relativeDestinationPath, array('originalFile' => $source, 'options' => $options, 'desiredName' => $desiredName)); $destinationFileName = $this->getUnocupiedName($desiredName, $relativeDestinationPath); $reflection = $relativeDestinationPath . $destinationFileName; $this->storeReflectionRecord($source, $reflection, $options); return $reflection; }
/** * Handle uploads made using PlUpload library * @param bool $secureFolder * @throws \Ip\Exception\Repository\Upload */ public function handlePlupload($secureFolder) { if (!$secureFolder && !ipAdminId()) { throw new \Ip\Exception\Repository\Upload("Trying to upload image to temporary directory without permission."); } if ($secureFolder) { $targetDir = ipFile('file/secure/tmp/'); } else { $targetDir = ipFile('file/tmp/'); } if ($secureFolder) { $sizeLimit = ipGetOption('Repository.publicUploadLimit', 4000); if ($this->folderSize($targetDir) > $sizeLimit * 1000000) { //4000 Mb by default ipLog()->error("Repository.publicUploadLimitReached: IP: `{ip}`. CurrentLimit `{limit}Mb`. Please update Repository.publicUploadLimit option to increase the limits.", array('ip' => $_SERVER['REMOTE_ADDR'], 'limit' => $sizeLimit)); throw new \Ip\Exception("Upload limit reached"); } } // Get parameters $chunk = isset($_REQUEST["chunk"]) ? $_REQUEST["chunk"] : 0; $chunks = isset($_REQUEST["chunks"]) ? $_REQUEST["chunks"] : 0; $fileName = isset($_REQUEST["name"]) ? $_REQUEST["name"] : ''; // Clean the fileName for security reasons $fileName = \Ip\Internal\File\Functions::cleanupFileName($fileName); // Make sure the fileName is unique but only if chunking is disabled if ($chunks < 2 && file_exists($targetDir . $fileName)) { $fileName = \Ip\Internal\File\Functions::genUnoccupiedName($fileName, $targetDir); } //security check $fileExtension = strtolower(substr($fileName, strrpos($fileName, '.') + 1)); $whiteListExtensions = array('jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'asf', 'asx', 'wmv', 'wmx', 'wm', 'avi', 'divx', 'flv', 'mov', 'qt', 'mpeg', 'mpg', 'mpe', 'mp4', 'm4v', 'ogv', 'webm', 'mkv', 'txt', 'asc', 'c', 'cc', 'h', 'csv', 'tsv', 'ics', 'rtx', 'css', 'htm', 'html', 'vtt', 'mp3', 'm4a', 'm4b', 'ra', 'ram', 'wav', 'ogg', 'oga', 'mid', 'midi', 'wma', 'wax', 'mka', 'rtf', 'js', 'pdf', 'class', 'tar', 'zip', 'gz', 'gzip', 'rar', '7z', 'doc', 'pot', 'pps', 'ppt', 'wri', 'xla', 'xls', 'xlt', 'xlw', 'mdb', 'mpp', 'docx', 'docm', 'dotx', 'dotm', 'eps', 'xlsx', 'xlsm', 'xlsb', 'xltx', 'xltm', 'xlam', 'pptx', 'pptm', 'ppsx', 'ppsm', 'potx', 'potm', 'ppam', 'sldx', 'sldm', 'onetoc', 'onetoc2', 'onetmp', 'onepkg', 'odt', 'odp', 'ods', 'odg', 'odc', 'odb', 'odf', 'wp', 'wpd', 'key', 'numbers', 'pages', 'xml', 'json', 'iso', 'aac', 'img', 'psd', 'ai', 'sql', 'swf', 'svg'); $whiteListExtensions = ipFilter('ipWhiteListExtensions', $whiteListExtensions); if (!empty($fileExtension) && !in_array($fileExtension, $whiteListExtensions)) { //security risk throw new \Ip\Exception\Repository\Upload\ForbiddenFileExtension("Files with extension (." . esc($fileExtension) . ") are not permitted for security reasons.", array('extension' => $fileExtension, 'filename' => $fileName)); } //end security check // Look for the content type header $contentType = null; if (isset($_SERVER["HTTP_CONTENT_TYPE"])) { $contentType = $_SERVER["HTTP_CONTENT_TYPE"]; } if (isset($_SERVER["CONTENT_TYPE"])) { $contentType = $_SERVER["CONTENT_TYPE"]; } // Handle non multipart uploads older WebKit versions didn't support multipart in HTML5 if (strpos($contentType, "multipart") !== false) { if (!isset($_FILES['file']['tmp_name']) || !is_uploaded_file($_FILES['file']['tmp_name'])) { throw new \Ip\Exception\Repository\Upload("Failed to move uploaded file."); } // Open temp file $out = fopen($targetDir . $fileName, $chunk == 0 ? "wb" : "ab"); if (!$out) { throw new \Ip\Exception\Repository\Upload("Failed to open output stream."); } //mark this file as uploaded by current user $this->setFileUploadedByThisUser($targetDir . $fileName); // Read binary input stream and append it to temp file $in = fopen($_FILES['file']['tmp_name'], "rb"); if (!$in) { throw new \Ip\Exception\Repository\Upload("Failed to open input stream."); } while ($buff = fread($in, 4096)) { fwrite($out, $buff); } fclose($in); fclose($out); @unlink($_FILES['file']['tmp_name']); } else { // Open temp file $out = fopen($targetDir . '/' . $fileName, $chunk == 0 ? "wb" : "ab"); if (!$out) { throw new \Ip\Exception\Repository\Upload("Failed to open output stream."); } // Read binary input stream and append it to temp file $in = fopen("php://input", "rb"); if (!$in) { throw new \Ip\Exception\Repository\Upload("Failed to open input stream."); } while ($buff = fread($in, 4096)) { if (function_exists('set_time_limit')) { set_time_limit(30); } fwrite($out, $buff); } fclose($in); fclose($out); } $this->uploadedFileName = $fileName; $this->uploadedFile = $targetDir . $fileName; $this->targetDir = $targetDir; }
/** * Get unocupied file name in directory. Very useful when storing uploaded files. * * @param string $dir * @param string $desiredName * @param bool $sanitize clean up supicious symbols from file name * @return string */ function ipUnoccupiedFileName($dir, $desiredName, $sanitize = true) { $availableFileName = \Ip\Internal\File\Functions::genUnoccupiedName($desiredName, $dir, '', $sanitize); return $availableFileName; }
/** * @param string $imageFile * @param string $destDir * @param int $x1 * @param int $y1 * @param int $x2 * @param int $y2 * @param int $quality * @param int $widthDest * @param int $heightDest * @return string * @throws \Ip\Exception * @throws \Exception */ public static function crop($imageFile, $destDir, $x1, $y1, $x2, $y2, $quality, $widthDest, $heightDest) { if ($widthDest === null) { $widthDest = $x2 - $x1; } if ($heightDest === null) { $heightDest = $y2 - $y1; } $imageInfo = getimagesize($imageFile); if ($imageInfo[0] == $widthDest && $imageInfo[1] == $heightDest && $x1 == 0 && $y1 == 0) { // Don't need to crop or resize. $newName = \Ip\Internal\File\Functions::genUnoccupiedName($imageFile, $destDir); copy($imageFile, $destDir . $newName); return $newName; } if (!self::getMemoryNeeded($imageFile)) { throw new \Ip\Exception("Can't get memory needed", self::ERROR_MEMORY); } try { $image = self::createImageImage($imageFile); } catch (\Exception $e) { throw new \Ip\Exception($e->getMessage(), $e->getCode(), $e); } if ($x2 - $x1 > imagesx($image) || $y2 - $y1 > imagesy($image) || $x1 < 0 || $y1 < 0) { // Cropping area goes out of image edge. Fill transparent. /** * Negative coordinates x1, y1 are possible. * This part of code just adds tarnsparent edges in this way making $image required proportions. * We don't care about the size in this step. */ $tmpImage = imagecreatetruecolor($x2 - $x1, $y2 - $y1); imagealphablending($tmpImage, false); imagesavealpha($tmpImage, true); $color = imagecolorallocatealpha($tmpImage, 255, 255, 255, 127); imagefilledrectangle($tmpImage, 0, 0, $x2 - $x1, $y2 - $y1, $color); if ($x1 >= 0) { $sx1 = $x1; $dx1 = 0; } else { $sx1 = 0; $dx1 = -$x1; } if ($y1 >= 0) { $sy1 = $y1; $dy1 = 0; } else { $sy1 = 0; $dy1 = -$y1; } if ($x2 - $x1 > imagesx($image)) { $sx2 = imagesx($image); // $dx2 = $x2 - $x1; $dx2 = $dx1 + imagesx($image); } else { $sx2 = $x2; $dx2 = imagesx($tmpImage); } if ($y2 - $y1 > imagesy($image)) { $sy2 = imagesy($image); $dy2 = $dy1 + imagesy($image); } else { $sy2 = $y2; $dy2 = imagesy($tmpImage); } imagecopyresampled($tmpImage, $image, $dx1, $dy1, $sx1, $sy1, $dx2 - $dx1, $dy2 - $dy1, $sx2 - $sx1, $sy2 - $sy1); $image = $tmpImage; $sx1 = 0; $sy1 = 0; $sx2 = imagesx($image); $sy2 = imagesy($image); /* Transparency required. Transform to png. */ $mime = IMAGETYPE_PNG; $path_parts = pathinfo($imageFile); if ($path_parts['extension'] != 'png') { $tmpImageName = $path_parts['filename'] . '.png'; } else { $tmpImageName = $imageFile; } $newName = \Ip\Internal\File\Functions::genUnoccupiedName($tmpImageName, $destDir); } else { $sx1 = $x1; $sx2 = $x2; $sy1 = $y1; $sy2 = $y2; $mime = self::getMimeType($imageFile); $newName = \Ip\Internal\File\Functions::genUnoccupiedName($imageFile, $destDir); } /** * Our $image is required proportions. The only thing we need to do is to scale the image and save. */ $imageNew = imagecreatetruecolor($widthDest, $heightDest); imagealphablending($imageNew, false); imagesavealpha($imageNew, true); $color = imagecolorallocatealpha($imageNew, 255, 255, 255, 127); imagefilledrectangle($imageNew, 0, 0, $widthDest, $heightDest, $color); imagecopyresampled($imageNew, $image, 0, 0, $sx1, $sy1, $widthDest, $heightDest, $sx2 - $sx1, $sy2 - $sy1); $newFile = $destDir . $newName; try { self::saveImage($imageNew, $newFile, $quality, $mime); } catch (\Exception $e) { throw new \Exception($e->getMessage(), $e->getCode(), $e); } return $newName; }
/** * @param string $relativePath * @param string $destinationDir * @return string */ public static function copyTemporaryFile($relativePath, $destinationDir) { $newBasename = \Ip\Internal\File\Functions::genUnoccupiedName($relativePath, $destinationDir); if (!copy(ipFile('file/tmp/' . $relativePath), $destinationDir . $newBasename)) { trigger_error("Can't copy file from " . htmlspecialchars(ipThemeFile('') . $relativePath) . ' to ' . htmlspecialchars($destinationDir . $newBasename)); } return $newBasename; }