1<?php 2/** 3 * Smarty write file plugin 4 * 5 * @package Smarty 6 * @subpackage PluginsInternal 7 * @author Monte Ohrt 8 */ 9 10/** 11 * Smarty Internal Write File Class 12 * 13 * @package Smarty 14 * @subpackage PluginsInternal 15 */ 16class Smarty_Internal_Runtime_WriteFile 17{ 18 /** 19 * Writes file in a safe way to disk 20 * 21 * @param string $_filepath complete filepath 22 * @param string $_contents file content 23 * @param Smarty $smarty smarty instance 24 * 25 * @throws SmartyException 26 * @return boolean true 27 */ 28 public function writeFile($_filepath, $_contents, Smarty $smarty) 29 { 30 $_error_reporting = error_reporting(); 31 error_reporting($_error_reporting & ~E_NOTICE & ~E_WARNING); 32 $_file_perms = property_exists($smarty, '_file_perms') ? $smarty->_file_perms : 0644; 33 $_dir_perms = 34 property_exists($smarty, '_dir_perms') ? (isset($smarty->_dir_perms) ? $smarty->_dir_perms : 0777) : 0771; 35 if ($_file_perms !== null) { 36 $old_umask = umask(0); 37 } 38 $_dirpath = dirname($_filepath); 39 // if subdirs, create dir structure 40 if ($_dirpath !== '.') { 41 $i = 0; 42 // loop if concurrency problem occurs 43 // see https://bugs.php.net/bug.php?id=35326 44 while (!is_dir($_dirpath)) { 45 if (@mkdir($_dirpath, $_dir_perms, true)) { 46 break; 47 } 48 clearstatcache(); 49 if (++$i === 3) { 50 error_reporting($_error_reporting); 51 throw new SmartyException("unable to create directory {$_dirpath}"); 52 } 53 sleep(1); 54 } 55 } 56 // write to tmp file, then move to overt file lock race condition 57 $_tmp_file = $_dirpath . DIRECTORY_SEPARATOR . str_replace(array('.', ','), '_', uniqid('wrt', true)); 58 if (!file_put_contents($_tmp_file, $_contents)) { 59 error_reporting($_error_reporting); 60 throw new SmartyException("unable to write file {$_tmp_file}"); 61 } 62 /* 63 * Windows' rename() fails if the destination exists, 64 * Linux' rename() properly handles the overwrite. 65 * Simply unlink()ing a file might cause other processes 66 * currently reading that file to fail, but linux' rename() 67 * seems to be smart enough to handle that for us. 68 */ 69 if (Smarty::$_IS_WINDOWS) { 70 // remove original file 71 if (is_file($_filepath)) { 72 @unlink($_filepath); 73 } 74 // rename tmp file 75 $success = @rename($_tmp_file, $_filepath); 76 } else { 77 // rename tmp file 78 $success = @rename($_tmp_file, $_filepath); 79 if (!$success) { 80 // remove original file 81 if (is_file($_filepath)) { 82 @unlink($_filepath); 83 } 84 // rename tmp file 85 $success = @rename($_tmp_file, $_filepath); 86 } 87 } 88 if (!$success) { 89 error_reporting($_error_reporting); 90 throw new SmartyException("unable to write file {$_filepath}"); 91 } 92 if ($_file_perms !== null) { 93 // set file permissions 94 chmod($_filepath, $_file_perms); 95 umask($old_umask); 96 } 97 error_reporting($_error_reporting); 98 return true; 99 } 100} 101