1<?php 2 3namespace RainLoop\Providers\Storage; 4 5class FileStorage implements \RainLoop\Providers\Storage\IStorage 6{ 7 /** 8 * @var string 9 */ 10 private $sDataPath; 11 12 /** 13 * @var bool 14 */ 15 private $bLocal; 16 17 /** 18 * @var \MailSo\Log\Logger 19 */ 20 protected $oLogger; 21 22 /** 23 * @param string $sStoragePath 24 * @param bool $bLocal = false 25 * 26 * @return void 27 */ 28 public function __construct($sStoragePath, $bLocal = false) 29 { 30 $this->sDataPath = \rtrim(\trim($sStoragePath), '\\/'); 31 $this->bLocal = !!$bLocal; 32 $this->oLogger = null; 33 } 34 35 /** 36 * @param \RainLoop\Model\Account|string|null $oAccount 37 * @param int $iStorageType 38 * @param string $sKey 39 * @param string $sValue 40 * 41 * @return bool 42 */ 43 public function Put($oAccount, $iStorageType, $sKey, $sValue) 44 { 45 return false !== @\file_put_contents( 46 $this->generateFileName($oAccount, $iStorageType, $sKey, true), $sValue); 47 } 48 49 /** 50 * @param \RainLoop\Model\Account|string|null $oAccount 51 * @param int $iStorageType 52 * @param string $sKey 53 * @param mixed $mDefault = false 54 * 55 * @return mixed 56 */ 57 public function Get($oAccount, $iStorageType, $sKey, $mDefault = false) 58 { 59 $mValue = false; 60 $sFileName = $this->generateFileName($oAccount, $iStorageType, $sKey); 61 if (\file_exists($sFileName)) 62 { 63 $mValue = \file_get_contents($sFileName); 64 } 65 66 return false === $mValue ? $mDefault : $mValue; 67 } 68 69 /** 70 * @param \RainLoop\Model\Account|string|null $oAccount 71 * @param int $iStorageType 72 * @param string $sKey 73 * 74 * @return bool 75 */ 76 public function Clear($oAccount, $iStorageType, $sKey) 77 { 78 $mResult = true; 79 $sFileName = $this->generateFileName($oAccount, $iStorageType, $sKey); 80 if (\file_exists($sFileName)) 81 { 82 $mResult = @\unlink($sFileName); 83 } 84 85 return $mResult; 86 } 87 88 /** 89 * @param \RainLoop\Model\Account|string $oAccount 90 * 91 * @return bool 92 */ 93 public function DeleteStorage($oAccount) 94 { 95 $sPath = $this->generateFileName($oAccount, 96 \RainLoop\Providers\Storage\Enumerations\StorageType::USER, 'xxx', false, true); 97 98 if (!empty($sPath) && \is_dir($sPath)) 99 { 100 \MailSo\Base\Utils::RecRmDir($sPath); 101 } 102 103 $sPath = $this->generateFileName($oAccount, 104 \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, 'xxx', false, true); 105 106 if (!empty($sPath) && \is_dir($sPath)) 107 { 108 \MailSo\Base\Utils::RecRmDir($sPath); 109 } 110 111 return true; 112 } 113 114 /** 115 * @return bool 116 */ 117 public function IsLocal() 118 { 119 return $this->bLocal; 120 } 121 122 /** 123 * @param \RainLoop\Model\Account|string|null $mAccount 124 * @param int $iStorageType 125 * @param string $sKey 126 * @param bool $bMkDir = false 127 * @param bool $bForDeleteAction = false 128 * 129 * @return string 130 */ 131 public function generateFileName($mAccount, $iStorageType, $sKey, $bMkDir = false, $bForDeleteAction = false) 132 { 133 if (null === $mAccount) 134 { 135 $iStorageType = \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY; 136 } 137 138 $sEmail = $sSubEmail = ''; 139 if ($mAccount instanceof \RainLoop\Model\Account) 140 { 141 $sEmail = $mAccount->ParentEmailHelper(); 142 if ($this->bLocal && $mAccount->IsAdditionalAccount() && !$bForDeleteAction) 143 { 144 $sSubEmail = $mAccount->Email(); 145 } 146 } 147 148 if (\is_string($mAccount) && empty($sEmail)) 149 { 150 $sEmail = $mAccount; 151 } 152 153 $sEmail = \preg_replace('/[^a-z0-9\-\.@]+/i', '_', $sEmail); 154 $sSubEmail = \preg_replace('/[^a-z0-9\-\.@]+/i', '_', $sSubEmail); 155 156 $sTypePath = $sKeyPath = ''; 157 switch ($iStorageType) 158 { 159 default: 160 case \RainLoop\Providers\Storage\Enumerations\StorageType::USER: 161 case \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY: 162 $sTypePath = 'data'; 163 $sKeyPath = \md5($sKey); 164 $sKeyPath = \substr($sKeyPath, 0, 2).'/'.$sKeyPath; 165 break; 166 case \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG: 167 $sTypePath = 'cfg'; 168 $sKeyPath = \preg_replace('/[_]+/', '_', \preg_replace('/[^a-zA-Z0-9\/]/', '_', $sKey)); 169 break; 170 } 171 172 $sFilePath = ''; 173 if (\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY === $iStorageType) 174 { 175 $sFilePath = $this->sDataPath.'/'.$sTypePath.'/__nobody__/'.$sKeyPath; 176 } 177 else if (!empty($sEmail)) 178 { 179 $sFilePath = $this->sDataPath.'/'.$sTypePath.'/'. 180 \str_pad(\rtrim(\substr($sEmail, 0, 2), '@'), 2, '_').'/'.$sEmail.'/'. 181 (0 < \strlen($sSubEmail) ? $sSubEmail.'/' : ''). 182 ($bForDeleteAction ? '' : $sKeyPath); 183 } 184 185 if ($bMkDir && !$bForDeleteAction && !empty($sFilePath) && !@\is_dir(\dirname($sFilePath))) 186 { 187 if (!@\mkdir(\dirname($sFilePath), 0755, true)) 188 { 189 throw new \RainLoop\Exceptions\Exception('Can\'t make storage directory "'.$sFilePath.'"'); 190 } 191 } 192 193 return $sFilePath; 194 } 195 196 /** 197 * @param \MailSo\Log\Logger $oLogger 198 */ 199 public function SetLogger($oLogger) 200 { 201 $this->oLogger = $oLogger instanceof \MailSo\Log\Logger ? $oLogger : null; 202 } 203} 204