Example #1
0
 /**
  * Saves $data to the cache
  * 
  * @param string $data
  * @return bool
  *
  */
 public function save($data)
 {
     $filename = $this->buildFilename();
     if (!is_file($filename)) {
         $dirname = dirname($filename);
         if (is_dir($dirname)) {
             $files = glob("{$dirname}/*.*");
             $numFiles = count($files);
             if ($numFiles >= self::maxCacheFiles) {
                 // if the cache file doesn't already exist, and there are too many files here
                 // then abort the cache save for security (we don't want to fill up the disk)
                 // also go through and remove any expired files while we are here, to avoid
                 // this limit interrupting more cache saves.
                 foreach ($files as $file) {
                     if (self::isCacheFile($file) && $this->isCacheFileExpired($file)) {
                         $this->removeFilename($file);
                     }
                 }
                 return false;
             }
         } else {
             wireMkdir("{$dirname}/", true);
         }
     }
     $result = file_put_contents($filename, $data);
     wireChmod($filename);
     return $result;
 }
 /**
  * Start a new backup file, adding our info header to the top
  * 
  * @param string $file
  * @param array $options
  * @return bool
  * 
  */
 protected function backupStartFile($file, array $options)
 {
     $fp = fopen($file, 'w+');
     if (!$fp) {
         $this->error("Unable to write header to file: {$file}");
         return false;
     }
     $info = array('time' => date('Y-m-d H:i:s'), 'user' => $options['user'], 'dbName' => $this->databaseConfig['dbName'], 'description' => $options['description'], 'tables' => $options['tables'], 'excludeTables' => $options['excludeTables'], 'excludeCreateTables' => $options['excludeCreateTables'], 'excludeExportTables' => $options['excludeExportTables']);
     $json = json_encode($info);
     $json = str_replace(array("\r", "\n"), " ", $json);
     fwrite($fp, self::fileHeader . " {$json}\n");
     fclose($fp);
     if (function_exists('wireChmod')) {
         wireChmod($file);
     }
     return true;
 }
Example #3
0
 /**
  * Hookable version of size() with implementation
  *	
  * See comments for size() method above.
  * 
  * @param int $width
  * @param int $height
  * @param array|string|int $options
  * @return Pageimage
  *
  */
 protected function ___size($width, $height, $options)
 {
     // I was getting unnecessarily resized images without this code below,
     // but this may be better solved in ImageSizer?
     /*
     $w = $this->width();
     $h = $this->height();
     if($w == $width && $h == $height) return $this; 
     if(!$height && $w == $width) return $this; 
     if(!$width && $h == $height) return $this; 
     */
     if ($this->ext == 'svg') {
         return $this;
     }
     if (!is_array($options)) {
         if (is_string($options)) {
             // optionally allow a string to be specified with crop direction, for shorter syntax
             if (strpos($options, ',') !== false) {
                 $options = explode(',', $options);
             }
             // 30,40
             $options = array('cropping' => $options);
         } else {
             if (is_int($options)) {
                 // optionally allow an integer to be specified with quality, for shorter syntax
                 $options = array('quality' => $options);
             } else {
                 if (is_bool($options)) {
                     // optionally allow a boolean to be specified with upscaling toggle on/off
                     $options = array('upscaling' => $options);
                 } else {
                     // unknown options type
                     $options = array();
                 }
             }
         }
     }
     $defaultOptions = array('upscaling' => true, 'cropping' => true, 'quality' => 90, 'hidpiQuality' => 40, 'suffix' => array(), 'forceNew' => false, 'hidpi' => false, 'cleanFilename' => false, 'rotate' => 0, 'flip' => '');
     $this->error = '';
     $configOptions = wire('config')->imageSizerOptions;
     if (!is_array($configOptions)) {
         $configOptions = array();
     }
     $options = array_merge($defaultOptions, $configOptions, $options);
     $width = (int) $width;
     $height = (int) $height;
     if (is_string($options['cropping']) && strpos($options['cropping'], 'x') === 0 && preg_match('/^x(\\d+)[yx](\\d+)/', $options['cropping'], $matches)) {
         $options['cropping'] = true;
         $options['cropExtra'] = array((int) $matches[1], (int) $matches[2], $width, $height);
         $crop = '';
     } else {
         $crop = ImageSizer::croppingValueStr($options['cropping']);
     }
     if (!is_array($options['suffix'])) {
         // convert to array
         $options['suffix'] = empty($options['suffix']) ? array() : explode(' ', $options['suffix']);
     }
     if ($options['rotate'] && !in_array(abs((int) $options['rotate']), array(90, 180, 270))) {
         $options['rotate'] = 0;
     }
     if ($options['rotate']) {
         $options['suffix'][] = ($options['rotate'] > 0 ? "rot" : "tor") . abs($options['rotate']);
     }
     if ($options['flip']) {
         $options['suffix'][] = strtolower(substr($options['flip'], 0, 1)) == 'v' ? 'flipv' : 'fliph';
     }
     $suffixStr = '';
     if (!empty($options['suffix'])) {
         $suffix = $options['suffix'];
         sort($suffix);
         foreach ($suffix as $key => $s) {
             $s = strtolower($this->wire('sanitizer')->fieldName($s));
             if (empty($s)) {
                 unset($suffix[$key]);
             } else {
                 $suffix[$key] = $s;
             }
         }
         if (count($suffix)) {
             $suffixStr = '-' . implode('-', $suffix);
         }
     }
     if ($options['hidpi']) {
         $suffixStr .= '-hidpi';
         if ($options['hidpiQuality']) {
             $options['quality'] = $options['hidpiQuality'];
         }
     }
     //$basename = $this->pagefiles->cleanBasename($this->basename(), false, false, false);
     // cleanBasename($basename, $originalize = false, $allowDots = true, $translate = false)
     $basename = basename($this->basename(), "." . $this->ext());
     // i.e. myfile
     if ($options['cleanFilename'] && strpos($basename, '.') !== false) {
         $basename = substr($basename, 0, strpos($basename, '.'));
     }
     $basename .= '.' . $width . 'x' . $height . $crop . $suffixStr . "." . $this->ext();
     // i.e. myfile.100x100.jpg or myfile.100x100nw-suffix1-suffix2.jpg
     $filenameFinal = $this->pagefiles->path() . $basename;
     $filenameUnvalidated = '';
     $exists = file_exists($filenameFinal);
     if (!$exists || $options['forceNew']) {
         $filenameUnvalidated = $this->pagefiles->page->filesManager()->getTempPath() . $basename;
         if ($exists && $options['forceNew']) {
             @unlink($filenameFinal);
         }
         if (file_exists($filenameUnvalidated)) {
             @unlink($filenameUnvalidated);
         }
         if (@copy($this->filename(), $filenameUnvalidated)) {
             try {
                 $sizer = new ImageSizer($filenameUnvalidated);
                 $sizer->setOptions($options);
                 if ($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) {
                     wireChmod($filenameFinal);
                 } else {
                     $this->error = "ImageSizer::resize({$width}, {$height}) failed for {$filenameUnvalidated}";
                 }
             } catch (Exception $e) {
                 $this->trackException($e, false);
                 $this->error = $e->getMessage();
             }
         } else {
             $this->error("Unable to copy {$this->filename} => {$filenameUnvalidated}");
         }
     }
     $pageimage = clone $this;
     // if desired, user can check for property of $pageimage->error to see if an error occurred.
     // if an error occurred, that error property will be populated with details
     if ($this->error) {
         // error condition: unlink copied file
         if (is_file($filenameFinal)) {
             @unlink($filenameFinal);
         }
         if ($filenameUnvalidated && is_file($filenameUnvalidated)) {
             @unlink($filenameUnvalidated);
         }
         // write an invalid image so it's clear something failed
         // todo: maybe return a 1-pixel blank image instead?
         $data = "This is intentionally invalid image data.\n{$this->error}";
         if (file_put_contents($filenameFinal, $data) !== false) {
             wireChmod($filenameFinal);
         }
         // we also tell PW about it for logging and/or admin purposes
         $this->error($this->error);
     }
     $pageimage->setFilename($filenameFinal);
     $pageimage->setOriginal($this);
     return $pageimage;
 }
Example #4
0
/**
* Change the mode of a file or directory, consistent with PW's chmodFile/chmodDir settings
* 
* @param string $path May be a directory or a filename
* @param bool $recursive If set to true, all files and directories in $path will be recursively set as well.
* @param string If you want to set the mode to something other than PW's chmodFile/chmodDir settings, 
	you may override it by specifying it here. Ignored otherwise. Format should be a string, like "0755".
* @return bool Returns true if all changes were successful, or false if at least one chmod failed. 
* @throws WireException when it receives incorrect chmod format
*
*/
function wireChmod($path, $recursive = false, $chmod = null)
{
    if (is_null($chmod)) {
        // default: pull values from PW config
        $chmodFile = wire('config')->chmodFile;
        $chmodDir = wire('config')->chmodDir;
    } else {
        // optional, manually specified string
        if (!is_string($chmod)) {
            throw new WireException("chmod must be specified as a string like '0755'");
        }
        $chmodFile = $chmod;
        $chmodDir = $chmod;
    }
    $numFails = 0;
    if (is_dir($path)) {
        // $path is a directory
        if ($chmodDir) {
            if (!@chmod($path, octdec($chmodDir))) {
                $numFails++;
            }
        }
        // change mode of files in directory, if recursive
        if ($recursive) {
            foreach (new DirectoryIterator($path) as $file) {
                if ($file->isDot()) {
                    continue;
                }
                $mod = $file->isDir() ? $chmodDir : $chmodFile;
                if ($mod) {
                    if (!@chmod($file->getPathname(), octdec($mod))) {
                        $numFails++;
                    }
                }
                if ($file->isDir()) {
                    if (!wireChmod($file->getPathname(), true, $chmod)) {
                        $numFails++;
                    }
                }
            }
        }
    } else {
        // $path is a file
        $mod = $chmodFile;
        if ($mod) {
            if (!@chmod($path, octdec($mod))) {
                $numFails++;
            }
        }
    }
    return $numFails == 0;
}
 /**
  * Save submitted admin account form
  *
  */
 protected function adminAccountSave($wire)
 {
     $input = $wire->input;
     $sanitizer = $wire->sanitizer;
     if (!$input->post->username || !$input->post->userpass) {
         $this->err("Missing account information");
     }
     if ($input->post->userpass !== $input->post->userpass_confirm) {
         $this->err("Passwords do not match");
     }
     if (strlen($input->post->userpass) < 6) {
         $this->err("Password must be at least 6 characters long");
     }
     $username = $sanitizer->pageName($input->post->username);
     if ($username != $input->post->username) {
         $this->err("Username must be only a-z 0-9");
     }
     if (strlen($username) < 2) {
         $this->err("Username must be at least 2 characters long");
     }
     $adminName = $sanitizer->pageName($input->post->admin_name);
     if ($adminName != $input->post->admin_name) {
         $this->err("Admin login URL must be only a-z 0-9");
     }
     if ($adminName == 'wire' || $adminName == 'site') {
         $this->err("Admin name may not be 'wire' or 'site'");
     }
     if (strlen($adminName) < 2) {
         $this->err("Admin login URL must be at least 2 characters long");
     }
     $email = strtolower($sanitizer->email($input->post->useremail));
     if ($email != strtolower($input->post->useremail)) {
         $this->err("Email address did not validate");
     }
     if ($this->numErrors) {
         return $this->adminAccount($wire);
     }
     $superuserRole = $wire->roles->get("name=superuser");
     $user = $wire->users->get($wire->config->superUserPageID);
     if (!$user->id) {
         $user = new User();
         $user->id = $wire->config->superUserPageID;
     }
     $user->name = $username;
     $user->pass = $input->post->userpass;
     $user->email = $email;
     if (!$user->roles->has("superuser")) {
         $user->roles->add($superuserRole);
     }
     $admin = $wire->pages->get($wire->config->adminRootPageID);
     $admin->of(false);
     $admin->name = $adminName;
     try {
         if (self::TEST_MODE) {
             $this->ok("TEST MODE: skipped user creation");
         } else {
             $wire->users->save($user);
             $wire->pages->save($admin);
         }
     } catch (Exception $e) {
         $this->err($e->getMessage());
         return $this->adminAccount($wire);
     }
     $adminName = htmlentities($adminName, ENT_QUOTES, "UTF-8");
     $this->h("Admin Account Saved");
     $this->ok("User account saved: <b>{$user->name}</b>");
     $colors = $wire->sanitizer->pageName($input->post->colors);
     if (!in_array($colors, $this->colors)) {
         $colors = reset($this->colors);
     }
     $theme = $wire->modules->getInstall('AdminThemeDefault');
     $configData = $wire->modules->getModuleConfigData('AdminThemeDefault');
     $configData['colors'] = $colors;
     $wire->modules->saveModuleConfigData('AdminThemeDefault', $configData);
     $this->ok("Saved admin color set <b>{$colors}</b> - you will see this when you login.");
     $this->h("Complete &amp; Secure Your Installation");
     $this->getRemoveableItems($wire, false, true);
     $this->ok("Note that future runtime errors are logged to <b>/site/assets/logs/errors.txt</b> (not web accessible).");
     $this->ok("For more configuration options see <b>/wire/config.php</b>.");
     $this->warn("Please make your <b>/site/config.php</b> file non-writable, and readable only to you and Apache.");
     $this->p("<a target='_blank' href='https://processwire.com/docs/security/file-permissions/#securing-your-site-config.php-file'>How to secure your /site/config.php file <i class='fa fa-angle-right'></i></a>");
     if (is_writable("./site/modules/")) {
         wireChmod("./site/modules/", true);
     }
     $this->h("Use The Site!");
     $this->ok("Your admin URL is <a href='./{$adminName}/'>/{$adminName}/</a>");
     $this->p("If you'd like, you may change this later by editing the admin page and changing the name.", "detail");
     $this->btn("Login to Admin", 1, 'sign-in', false, true, "./{$adminName}/");
     $this->btn("View Site ", 1, 'angle-right', true, false, "./");
     // set a define that indicates installation is completed so that this script no longer runs
     if (!self::TEST_MODE) {
         file_put_contents("./site/assets/installed.php", "<?php // The existence of this file prevents the installer from running. Don't delete it unless you want to re-run the install or you have deleted ./install.php.");
     }
 }
 /**
  * Prune log file to specified number of bytes (from the end)
  * 
  * @param int $bytes
  * @return int|bool positive integer on success, 0 if no prune necessary, or boolean false on failure.
  * 
  */
 public function pruneBytes($bytes)
 {
     $filename = $this->logFilename;
     if (!$filename || filesize($filename) <= $bytes) {
         return 0;
     }
     $fpr = fopen($filename, "r");
     $fpw = fopen("{$filename}.new", "w");
     if (!$fpr || !$fpw) {
         return false;
     }
     fseek($fpr, $bytes * -1, SEEK_END);
     fgets($fpr, self::maxLineLength);
     // first line likely just a partial line, so skip it
     $cnt = 0;
     while (!feof($fpr)) {
         $line = fgets($fpr, self::maxLineLength);
         fwrite($fpw, $line);
         $cnt++;
     }
     fclose($fpw);
     fclose($fpr);
     if ($cnt) {
         unlink($filename);
         rename("{$filename}.new", $filename);
         wireChmod($filename);
     } else {
         @unlink("{$filename}.new");
     }
     return $cnt;
 }
 /**
  * do the resizes like Pageimage does it
  *
  * @param object $caller
  * @param pageimage $img
  * @param string $targetFilename
  * @param array $options1
  * @param array $options2
  * @return pageimage
  */
 public static function renderImage(&$caller, &$img, $sourceFilename, $targetFilename, $width, $height, $options)
 {
     $filenameFinal = $targetFilename;
     $filenameUnvalidated = $img->pagefiles->page->filesManager()->getTempPath() . basename($targetFilename);
     if (file_exists($filenameFinal)) {
         @unlink($filenameFinal);
     }
     if (file_exists($filenameUnvalidated)) {
         @unlink($filenameUnvalidated);
     }
     if (@copy($sourceFilename, $filenameUnvalidated)) {
         try {
             $sizer = new ImageSizer($filenameUnvalidated);
             $sizer->setOptions($options);
             if ($sizer->resize($width, $height) && @rename($filenameUnvalidated, $filenameFinal)) {
                 // if script runs into a timeout while in ImageSizer, we never will reach this line and we will stay with $filenameUnvalidated
                 if ($caller->config->chmodFile) {
                     chmod($filenameFinal, octdec($caller->config->chmodFile));
                 }
             } else {
                 $caller->error = "ImageSizer::resize({$width}, {$height}) failed for {$filenameUnvalidated}";
             }
         } catch (Exception $e) {
             $caller->error = $e->getMessage();
         }
     } else {
         $caller->error("Unable to copy {$sourceFilename} => {$filenameUnvalidated}");
     }
     $pageimage = clone $img;
     // if desired, user can check for property of $pageimage->error to see if an error occurred.
     // if an error occurred, that error property will be populated with details
     if ($caller->error) {
         // error condition: unlink copied file
         if (is_file($filenameFinal)) {
             @unlink($filenameFinal);
         }
         if (is_file($filenameUnvalidated)) {
             @unlink($filenameUnvalidated);
         }
         // write an invalid image so it's clear something failed
         $data = "This is intentionally invalid image data.\n{$caller->error}";
         if (file_put_contents($filenameFinal, $data) !== false) {
             wireChmod($filenameFinal);
         }
         // we also tell PW about it for logging and/or admin purposes
         $caller->error($caller->error);
     }
     $pageimage->setFilename($filenameFinal);
     $pageimage->setOriginal($img);
     return $pageimage;
 }
 /**
  * Unzip the module file to tempDir and then copy to destination directory
  *
  * @param string $file File to unzip
  * @param string $destinationDir Directory to copy completed files into. Optionally omit to determine automatically.
  * @return bool|string Returns destinationDir on success, false on failure
  * @throws WireException
  *
  */
 public function unzipModule($file, $destinationDir = '')
 {
     $success = false;
     $tempDir = $this->getTempDir();
     $mkdirDestination = false;
     try {
         $files = wireUnzipFile($file, $tempDir);
         if (is_file($file)) {
             unlink($file);
         }
         foreach ($files as $f) {
             $this->message("Extracted: {$f}", Notice::debug);
         }
     } catch (Exception $e) {
         $this->error($e->getMessage());
         if (is_file($file)) {
             unlink($file);
         }
         return false;
     }
     if (!$destinationDir) {
         $destinationDir = $this->determineDestinationDir($files);
         if (!$destinationDir) {
             throw new WireException($this->_('Unable to find any module files'));
         }
     }
     $this->message("Destination directory: {$destinationDir}", Notice::debug);
     $files0 = trim($files[0], '/');
     $extractedDir = is_dir("{$tempDir}/{$files0}") && substr($files0, 0, 1) != '.' ? "{$files0}/" : "";
     // now create module directory and copy files over
     if (is_dir($destinationDir)) {
         // destination dir already there, perhaps an older version of same module?
         // create a backup of it
         $hasBackup = $this->backupDir($destinationDir);
         if ($hasBackup) {
             wireMkdir($destinationDir, true);
         }
     } else {
         if (wireMkdir($destinationDir, true)) {
             $mkdirDestination = true;
         }
         $hasBackup = false;
     }
     // label to identify destinationDir in messages and errors
     $dirLabel = str_replace($this->config->paths->root, '/', $destinationDir);
     if (is_dir($destinationDir)) {
         $from = $tempDir . $extractedDir;
         if (wireCopy($from, $destinationDir)) {
             $this->message($this->_('Successfully copied files to new directory:') . ' ' . $dirLabel);
             wireChmod($destinationDir, true);
             $success = true;
         } else {
             $this->error($this->_('Unable to copy files to new directory:') . ' ' . $dirLabel);
             if ($hasBackup) {
                 $this->restoreDir($destinationDir);
             }
         }
     } else {
         $this->error($this->_('Could not create directory:') . ' ' . $dirLabel);
     }
     if (!$success) {
         $this->error($this->_('Unable to copy module files:') . ' ' . $dirLabel);
         if ($mkdirDestination && !wireRmdir($destinationDir, true)) {
             $this->error($this->_('Could not delete failed module dir:') . ' ' . $destinationDir, Notice::log);
         }
     }
     return $success ? $destinationDir : false;
 }
Example #9
0
 /**
  * Hookable version of size() with implementation
  *	
  * See comments for size() method above. 
  *
  */
 protected function ___size($width, $height, $options)
 {
     // I was getting unnecessarily resized images without this code below,
     // but this may be better solved in ImageSizer?
     /*
     $w = $this->width();
     $h = $this->height();
     if($w == $width && $h == $height) return $this; 
     if(!$height && $w == $width) return $this; 
     if(!$width && $h == $height) return $this; 
     */
     if ($this->ext == 'svg') {
         return $this;
     }
     if (!is_array($options)) {
         if (is_string($options)) {
             // optionally allow a string to be specified with crop direction, for shorter syntax
             if (strpos($options, ',') !== false) {
                 $options = explode(',', $options);
             }
             // 30,40
             $options = array('cropping' => $options);
         } else {
             if (is_int($options)) {
                 // optionally allow an integer to be specified with quality, for shorter syntax
                 $options = array('quality' => $options);
             } else {
                 if (is_bool($options)) {
                     // optionally allow a boolean to be specified with upscaling toggle on/off
                     $options = array('upscaling' => $options);
                 }
             }
         }
     }
     $defaultOptions = array('upscaling' => true, 'cropping' => true, 'quality' => 90, 'suffix' => array(), 'forceNew' => false);
     $this->error = '';
     $configOptions = wire('config')->imageSizerOptions;
     if (!is_array($configOptions)) {
         $configOptions = array();
     }
     $options = array_merge($defaultOptions, $configOptions, $options);
     $width = (int) $width;
     $height = (int) $height;
     $crop = ImageSizer::croppingValueStr($options['cropping']);
     $suffixStr = '';
     if (!empty($options['suffix'])) {
         $suffix = is_array($options['suffix']) ? $options['suffix'] : array($options['suffix']);
         sort($suffix);
         foreach ($suffix as $key => $s) {
             $s = strtolower($this->wire('sanitizer')->fieldName($s));
             if (empty($s)) {
                 unset($suffix[$key]);
             } else {
                 $suffix[$key] = $s;
             }
         }
         if (count($suffix)) {
             $suffixStr = '-' . implode('-', $suffix);
         }
     }
     $basename = basename($this->basename(), "." . $this->ext());
     // i.e. myfile
     $basename .= '.' . $width . 'x' . $height . $crop . $suffixStr . "." . $this->ext();
     // i.e. myfile.100x100.jpg or myfile.100x100nw-suffix1-suffix2.jpg
     $filename = $this->pagefiles->path() . $basename;
     $exists = file_exists($filename);
     if (!$exists || $options['forceNew']) {
         if ($exists && $options['forceNew']) {
             unlink($filename);
         }
         if (@copy($this->filename(), $filename)) {
             try {
                 $sizer = new ImageSizer($filename);
                 $sizer->setOptions($options);
                 if ($sizer->resize($width, $height)) {
                     if ($this->config->chmodFile) {
                         chmod($filename, octdec($this->config->chmodFile));
                     }
                 } else {
                     $this->error = "ImageSizer::resize({$width}, {$height}) failed for {$filename}";
                 }
             } catch (Exception $e) {
                 $this->error = $e->getMessage();
             }
         } else {
             $this->error("Unable to copy {$this->filename} => {$filename}");
         }
     }
     $pageimage = clone $this;
     // if desired, user can check for property of $pageimage->error to see if an error occurred.
     // if an error occurred, that error property will be populated with details
     if ($this->error) {
         // error condition: unlink copied file
         if (is_file($filename)) {
             unlink($filename);
         }
         // write an invalid image so it's clear something failed
         // todo: maybe return a 1-pixel blank image instead?
         $data = "This is intentionally invalid image data.\n{$this->error}";
         if (file_put_contents($filename, $data) !== false) {
             wireChmod($filename);
         }
         // we also tell PW about it for logging and/or admin purposes
         $this->error($this->error);
     }
     $pageimage->setFilename($filename);
     $pageimage->setOriginal($this);
     return $pageimage;
 }