dolibarr 23.0.3
memory.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2009-2010 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2021-2024 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 * or see https://www.gnu.org/
19 */
20
26global $shmkeys, $shmoffset;
27
28$shmkeys = array(
29 'main' => 1,
30 'admin' => 2,
31 'dict' => 3,
32 'companies' => 4,
33 'suppliers' => 5,
34 'products' => 6,
35 'commercial' => 7,
36 'compta' => 8,
37 'projects' => 9,
38 'cashdesk' => 10,
39 'agenda' => 11,
40 'bills' => 12,
41 'propal' => 13,
42 'boxes' => 14,
43 'banks' => 15,
44 'other' => 16,
45 'errors' => 17,
46 'members' => 18,
47 'ecm' => 19,
48 'orders' => 20,
49 'users' => 21,
50 'help' => 22,
51 'stocks' => 23,
52 'interventions' => 24,
53 'donations' => 25,
54 'contracts' => 26,
55);
56$shmoffset = 1000; // Max number of entries found into a language file. If too low, some entries will be overwritten.
57
58
59
71function dol_setcache($memoryid, $data, $expire = 0, $filecache = 0, $replace = 0)
72{
73 global $conf;
74
75 $result = 0;
76
77 if (strpos($memoryid, 'count_') === 0) { // The memoryid key start with 'count_...'
78 if (!getDolGlobalString('MAIN_CACHE_COUNT')) {
79 return 0;
80 }
81 }
82
83 if (isModEnabled('memcached') && class_exists('Memcached')) {
84 // Using a memcached server
85 global $dolmemcache;
86 if (empty($dolmemcache) || !is_object($dolmemcache)) {
87 $dolmemcache = new Memcached();
88 $tmparray = explode(':', getDolGlobalString('MEMCACHED_SERVER'));
89 $port = (empty($tmparray[1]) ? 0 : $tmparray[1]);
90 $result = $dolmemcache->addServer($tmparray[0], ($port || strpos($tmparray[0], '/') !== false) ? $port : 11211);
91 if (!$result) {
92 return -1;
93 }
94 }
95
96 $memoryid = session_name().'_'.$memoryid;
97 //$dolmemcache->setOption(Memcached::OPT_COMPRESSION, false);
98 $dolmemcache->add($memoryid, $data, $expire); // This fails if key already exists
99 $rescode = $dolmemcache->getResultCode();
100 if ($rescode == 0) {
101 return is_array($data) ? count($data) : (is_scalar($data) ? strlen($data) : 0);
102 } elseif (!empty($replace) && $rescode == Memcached::RES_NOTSTORED) {
103 $dolmemcache->replace($memoryid, $data, $expire); // This fails if key does not exists
104 $rescode = $dolmemcache->getResultCode();
105 if ($rescode == 0) {
106 return is_array($data) ? count($data) : (is_scalar($data) ? strlen($data) : 0);
107 } else {
108 return -$rescode;
109 }
110 } else {
111 return -$rescode;
112 }
113 } elseif (isModEnabled('memcached') && class_exists('Memcache')) { // This is a really not reliable cache ! Use Memcached instead.
114 // Using a memcache server
115 global $dolmemcache;
116 if (empty($dolmemcache) || !is_object($dolmemcache)) {
117 $dolmemcache = new Memcache();
118 $tmparray = explode(':', getDolGlobalString('MEMCACHED_SERVER'));
119 $port = (empty($tmparray[1]) ? 0 : $tmparray[1]);
120 $result = $dolmemcache->addServer($tmparray[0], ($port || strpos($tmparray[0], '/') !== false) ? $port : 11211);
121 if (!$result) {
122 return -1;
123 }
124 }
125
126 $memoryid = session_name().'_'.$memoryid;
127 //$dolmemcache->setOption(Memcached::OPT_COMPRESSION, false);
128 $result = $dolmemcache->add($memoryid, $data, 0, $expire); // This fails if key already exists
129 if ($result) {
130 return is_array($data) ? count($data) : (is_scalar($data) ? strlen($data) : 0);
131 } else {
132 return -1;
133 }
134 } elseif (getDolGlobalInt('MAIN_OPTIMIZE_SPEED') & 0x02) { // This is a really not reliable cache ! Use Memcached instead.
135 // Using shmop
136 $result = dol_setshmop($memoryid, $data, $expire);
137 } elseif ($filecache > 0) {
138 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
139 require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
140 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
141 $now = dol_now();
142 $memoryid = session_name().'_'.$memoryid;
143 $dircache = 'dolcache';
144 $pathcache = DOL_DATA_ROOT.'/'.$dircache;
145 if (!dol_is_dir($pathcache)) {
146 $result = dol_mkdir($pathcache);
147 if ($result < 0) {
148 return $result;
149 }
150 }
151 if ($expire != 0) {
152 $expire = dol_time_plus_duree($now, $expire, 's');
153 }
154
155 $cachedata = array("expire" => $expire, "data" => $data);
156 $cachejson = dolEncrypt(json_encode($cachedata));
157 if (!dol_is_file($pathcache.'/'.$memoryid.'.cache') || $replace > 0) {
158 $result = file_put_contents($pathcache.'/'.$memoryid.'.cache', $cachejson);
159 dolChmod($pathcache.'/'.$memoryid.'.cache');
160 } else {
161 return 0;
162 }
163 } else {
164 // No intersession cache system available, we use at least the perpage cache
165 $conf->cache['cachememory_'.$memoryid] = $data;
166 $result = is_array($data) ? count($data) : (is_scalar($data) ? strlen($data) : 0);
167 }
168
169 return $result;
170}
171
180function dol_getcache($memoryid, $filecache = 0)
181{
182 global $conf;
183
184 if (strpos($memoryid, 'count_') === 0) { // The memoryid key start with 'count_...'
185 if (!getDolGlobalString('MAIN_CACHE_COUNT')) {
186 return null;
187 }
188 }
189
190 // Using a memcached server
191 if (isModEnabled('memcached') && class_exists('Memcached')) {
192 global $m;
193 if (empty($m) || !is_object($m)) {
194 $m = new Memcached();
195 $tmparray = explode(':', getDolGlobalString('MEMCACHED_SERVER'));
196 $port = (empty($tmparray[1]) ? 0 : $tmparray[1]);
197 $result = $m->addServer($tmparray[0], ($port || strpos($tmparray[0], '/') !== false) ? $port : 11211);
198 if (!$result) {
199 return -1;
200 }
201 }
202
203 $memoryid = session_name().'_'.$memoryid;
204 //$m->setOption(Memcached::OPT_COMPRESSION, false);
205 //print "Get memoryid=".$memoryid;
206 $data = $m->get($memoryid);
207 $rescode = $m->getResultCode();
208 //print "memoryid=".$memoryid." - rescode=".$rescode." - count(response)=".json_encode($data)."\n<br>";
209 //var_dump($data);
210 if ($rescode == 0) {
211 return $data;
212 } elseif ($rescode == 16) { // = Memcached::MEMCACHED_NOTFOUND but this constant does not exists.
213 return null;
214 } else {
215 return -$rescode;
216 }
217 } elseif (isModEnabled('memcached') && class_exists('Memcache')) { // This is a really not reliable cache ! Use Memcached instead.
218 global $m;
219 if (empty($m) || !is_object($m)) {
220 $m = new Memcache();
221 $tmparray = explode(':', getDolGlobalString('MEMCACHED_SERVER'));
222 $port = (empty($tmparray[1]) ? 0 : $tmparray[1]);
223 $result = $m->addServer($tmparray[0], ($port || strpos($tmparray[0], '/') !== false) ? $port : 11211);
224 if (!$result) {
225 return -1;
226 }
227 }
228
229 $memoryid = session_name().'_'.$memoryid;
230 //$m->setOption(Memcached::OPT_COMPRESSION, false);
231 $data = $m->get($memoryid);
232 //print "memoryid=".$memoryid." - rescode=".$rescode." - data=".count($data)."\n<br>";
233 //var_dump($data);
234 if ($data) {
235 return $data;
236 } else {
237 return null; // There is no way to make a difference between NOTFOUND and error when using Memcache. So do not use it, use Memcached instead.
238 }
239 } elseif (getDolGlobalInt('MAIN_OPTIMIZE_SPEED') & 0x02) { // This is a really not reliable cache ! Use Memcached instead.
240 // Using shmop
241 $data = dol_getshmop($memoryid);
242 return $data;
243 } elseif ($filecache > 0) {
244 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
245 require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
246 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
247 $now = dol_now();
248 $memoryid = session_name().'_'.$memoryid;
249 $dircache = 'dolcache';
250 $pathcache = DOL_DATA_ROOT.'/'.$dircache;
251 if (!dol_is_file($pathcache.'/'.$memoryid.'.cache')) {
252 return null;
253 }
254 $data = file_get_contents($pathcache.'/'.$memoryid.'.cache');
255 if (!$data) {
256 return -1;
257 }
258 $json = json_decode(dolDecrypt($data));
259 if ($json->expire > $now) {
260 return $json->data;
261 } else {
262 $result = dol_delete_file($pathcache.'/'.$memoryid.'.cache');
263 if (!$result) {
264 return -2;
265 }
266 }
267 return null;
268 } else {
269 // No intersession cache system available, we use at least the perpage cache
270 if (isset($conf->cache['cachememory_'.$memoryid])) {
271 return $conf->cache['cachememory_'.$memoryid];
272 }
273 }
274
275 return null;
276}
277
278
279
286function dol_getshmopaddress($memoryid)
287{
288 global $shmkeys, $shmoffset;
289 if (empty($shmkeys[$memoryid])) { // No room reserved for this memoryid, no way to use cache
290 return 0;
291 }
292 return $shmkeys[$memoryid] + $shmoffset;
293}
294
301{
302 global $shmkeys;
303
304 $resarray = array();
305 foreach ($shmkeys as $key => $val) {
306 $result = dol_getshmop($key);
307 if (!is_numeric($result) || $result > 0) {
308 $resarray[$key] = $result;
309 }
310 }
311 return $resarray;
312}
313
322function dol_setshmop($memoryid, $data, $expire)
323{
324 global $shmkeys;
325
326 //print 'dol_setshmop memoryid='.$memoryid."<br>\n";
327 if (empty($shmkeys[$memoryid]) || !function_exists("shmop_write")) {
328 return 0;
329 }
330 $shmkey = dol_getshmopaddress($memoryid);
331 if (empty($shmkey)) {
332 return 0; // No key reserved for this memoryid, we can't cache this memoryid
333 }
334
335 $newdata = serialize($data);
336 $size = strlen($newdata);
337 //print 'dol_setshmop memoryid='.$memoryid." shmkey=".$shmkey." newdata=".$size."bytes<br>\n";
338 $handle = shmop_open($shmkey, 'c', 0644, 6 + $size);
339 if ($handle) {
340 $shm_bytes_written1 = shmop_write($handle, str_pad((string) $size, 6), 0);
341 $shm_bytes_written2 = shmop_write($handle, $newdata, 6);
342 if ($shm_bytes_written1 + $shm_bytes_written2 != 6 + dol_strlen($newdata)) {
343 print "Couldn't write the entire length of data\n";
344 }
345 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
346 shmop_close($handle);
347 return ($shm_bytes_written1 + $shm_bytes_written2);
348 } else {
349 print 'Error in shmop_open for memoryid='.$memoryid.' shmkey='.$shmkey.' 6+size=6+'.$size;
350 return -1;
351 }
352}
353
360function dol_getshmop($memoryid)
361{
362 global $shmkeys;
363
364 $data = null;
365
366 if (empty($shmkeys[$memoryid]) || !function_exists("shmop_open")) {
367 return null;
368 }
369 $shmkey = dol_getshmopaddress($memoryid);
370 if (empty($shmkey)) {
371 return null; // No key reserved for this memoryid, we can't cache this memoryid
372 }
373
374 //print 'dol_getshmop memoryid='.$memoryid." shmkey=".$shmkey."<br>\n";
375 $handle = @shmop_open($shmkey, 'a', 0, 0);
376 if ($handle) {
377 $size = (int) trim(shmop_read($handle, 0, 6));
378 if ($size) {
379 $data = unserialize(shmop_read($handle, 6, $size));
380 } else {
381 return -1;
382 }
383 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
384 shmop_close($handle);
385 } else {
386 return null; // Can't open existing block, so we suppose it was not created, so nothing were cached yet for the memoryid
387 }
388 return $data;
389}
dol_time_plus_duree($time, $duration_value, $duration_unit, $ruleforendofmonth=0)
Add a delay to a date.
Definition date.lib.php:125
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1, $nolog=0)
Remove a file or several files with a mask.
dol_is_file($pathoffile)
Return if path is a file.
dol_is_dir($folder)
Test if filename is a directory.
dol_now($mode='gmt')
Return date for now.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_setcache($memoryid, $data, $expire=0, $filecache=0, $replace=0)
Save data into a memory area shared by all users, all sessions on server.
dol_getcache($memoryid, $filecache=0)
Read a memory area shared by all users, all sessions on server.
dol_listshmop()
Return list of contents of all memory area shared.
dol_setshmop($memoryid, $data, $expire)
Save data into a memory area shared by all users, all sessions on server.
dol_getshmopaddress($memoryid)
Return shared memory address used to store dataset with key memoryid.
dol_getshmop($memoryid)
Read a memory area shared by all users, all sessions on server.
dolEncrypt($chain, $key='', $ciphering='', $forceseed='')
Encode a string with a symmetric encryption.
dolDecrypt($chain, $key='')
Decode a string with a symmetric encryption.