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