1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* +********************************************************************************** |
4
|
|
|
* The contents of this file are subject to the vtiger CRM Public License Version 1.0 |
5
|
|
|
* ("License"); You may not use this file except in compliance with the License |
6
|
|
|
* The Original Code is: vtiger CRM Open Source |
7
|
|
|
* The Initial Developer of the Original Code is vtiger. |
8
|
|
|
* Portions created by vtiger are Copyright (C) vtiger. |
9
|
|
|
* All Rights Reserved. |
10
|
|
|
* Contributor(s): YetiForce S.A. |
11
|
|
|
* ********************************************************************************** */ |
12
|
|
|
|
13
|
|
|
namespace vtlib; |
14
|
|
|
|
15
|
|
|
class Functions |
16
|
21 |
|
{ |
17
|
|
|
public static function getAllModules($isEntityType = true, $showRestricted = false, $presence = false, $colorActive = false, $ownedby = false) |
18
|
21 |
|
{ |
19
|
15 |
|
if (\App\Cache::has('moduleTabs', 'all')) { |
20
|
|
|
$moduleList = \App\Cache::get('moduleTabs', 'all'); |
21
|
14 |
|
} else { |
22
|
14 |
|
$moduleList = []; |
23
|
14 |
|
$rows = (new \App\Db\Query())->from('vtiger_tab')->all(); |
24
|
14 |
|
foreach ($rows as $row) { |
25
|
11 |
|
if (!\App\Cache::has('moduleTabById', $row['tabid'])) { |
26
|
|
|
\App\Cache::save('moduleTabById', $row['tabid'], $row); |
27
|
14 |
|
} |
28
|
11 |
|
if (!\App\Cache::has('moduleTabByName', $row['name'])) { |
29
|
|
|
\App\Cache::save('moduleTabByName', $row['name'], $row); |
30
|
14 |
|
} |
31
|
14 |
|
$row['tabid'] = (int) $row['tabid']; |
32
|
14 |
|
$row['presence'] = (int) $row['presence']; |
33
|
14 |
|
$row['tabsequence'] = (int) $row['tabsequence']; |
34
|
14 |
|
$row['customized'] = (int) $row['customized']; |
35
|
14 |
|
$row['ownedby'] = (int) $row['ownedby']; |
36
|
14 |
|
$row['isentitytype'] = (int) $row['isentitytype']; |
37
|
14 |
|
$row['coloractive'] = (int) $row['coloractive']; |
38
|
14 |
|
$row['type'] = (int) $row['type']; |
39
|
14 |
|
$row['premium'] = (int) $row['premium']; |
40
|
|
|
$moduleList[$row['tabid']] = $row; |
41
|
14 |
|
} |
42
|
|
|
\App\Cache::save('moduleTabs', 'all', $moduleList); |
43
|
21 |
|
} |
44
|
21 |
|
$restrictedModules = ['Dashboard', 'ModComments']; |
45
|
21 |
|
foreach ($moduleList as $id => $module) { |
46
|
14 |
|
if (!$showRestricted && \in_array($module['name'], $restrictedModules)) { |
47
|
|
|
unset($moduleList[$id]); |
48
|
21 |
|
} |
49
|
13 |
|
if ($isEntityType && 0 === (int) $module['isentitytype']) { |
50
|
|
|
unset($moduleList[$id]); |
51
|
21 |
|
} |
52
|
2 |
|
if (false !== $presence && (int) $module['presence'] !== $presence) { |
53
|
|
|
unset($moduleList[$id]); |
54
|
21 |
|
} |
55
|
|
|
if (false !== $colorActive && 1 !== (int) $module['coloractive']) { |
56
|
|
|
unset($moduleList[$id]); |
57
|
21 |
|
} |
58
|
2 |
|
if (false !== $ownedby && (int) $module['ownedby'] !== $ownedby) { |
59
|
|
|
unset($moduleList[$id]); |
60
|
|
|
} |
61
|
21 |
|
} |
62
|
|
|
return $moduleList; |
63
|
|
|
} |
64
|
84 |
|
|
65
|
|
|
public static function getModuleData($mixed) |
66
|
84 |
|
{ |
67
|
|
|
if (empty($mixed)) { |
68
|
|
|
\App\Log::error(__METHOD__ . ' - Required parameter missing'); |
69
|
|
|
|
70
|
|
|
return false; |
71
|
84 |
|
} |
72
|
84 |
|
$id = $name = null; |
73
|
69 |
|
if (is_numeric($mixed)) { |
74
|
69 |
|
$id = $mixed; |
75
|
47 |
|
if (\App\Cache::has('moduleTabById', $mixed)) { |
76
|
|
|
return \App\Cache::get('moduleTabById', $mixed); |
77
|
|
|
} |
78
|
58 |
|
} else { |
79
|
58 |
|
$name = (string) $mixed; |
80
|
32 |
|
if (\App\Cache::has('moduleTabByName', $name)) { |
81
|
|
|
return \App\Cache::get('moduleTabByName', $name); |
82
|
|
|
} |
83
|
59 |
|
} |
84
|
59 |
|
$moduleList = []; |
85
|
59 |
|
$rows = (new \App\Db\Query())->from('vtiger_tab')->all(); |
86
|
59 |
|
foreach ($rows as $row) { |
87
|
59 |
|
\App\Cache::save('moduleTabById', $row['tabid'], $row); |
88
|
59 |
|
\App\Cache::save('moduleTabByName', $row['name'], $row); |
89
|
|
|
$moduleList[$row['tabid']] = $row; |
90
|
59 |
|
} |
91
|
59 |
|
\App\Cache::save('moduleTabs', 'all', $moduleList); |
92
|
34 |
|
if ($name && \App\Cache::has('moduleTabByName', $name)) { |
93
|
|
|
return \App\Cache::get('moduleTabByName', $name); |
94
|
26 |
|
} |
95
|
|
|
return $id ? \App\Cache::get('moduleTabById', $id) : null; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
// MODULE RECORD |
99
|
|
|
protected static $crmRecordIdMetadataCache = []; |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Clear cache meta data for records. |
103
|
|
|
* |
104
|
|
|
* @param int $id |
105
|
1 |
|
*/ |
106
|
|
|
public static function clearCacheMetaDataRecord($id) |
107
|
1 |
|
{ |
108
|
1 |
|
if (isset(static::$crmRecordIdMetadataCache[$id])) { |
109
|
|
|
unset(static::$crmRecordIdMetadataCache[$id]); |
110
|
1 |
|
} |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* Function gets record metadata. |
115
|
|
|
* |
116
|
|
|
* @param array|int $mixedid |
117
|
|
|
* |
118
|
|
|
* @return array |
119
|
26 |
|
*/ |
120
|
|
|
public static function getCRMRecordMetadata($mixedid) |
121
|
26 |
|
{ |
122
|
|
|
$multimode = \is_array($mixedid); |
123
|
26 |
|
|
124
|
26 |
|
$ids = $multimode ? $mixedid : [$mixedid]; |
125
|
26 |
|
$missing = []; |
126
|
26 |
|
foreach ($ids as $id) { |
127
|
9 |
|
if ($id && !isset(self::$crmRecordIdMetadataCache[$id])) { |
128
|
|
|
$missing[] = $id; |
129
|
|
|
} |
130
|
26 |
|
} |
131
|
9 |
|
if ($missing) { |
132
|
9 |
|
$query = (new \App\Db\Query()) |
133
|
9 |
|
->select(['crmid', 'setype', 'deleted', 'smcreatorid', 'smownerid', 'createdtime', 'private']) |
134
|
9 |
|
->from('vtiger_crmentity') |
135
|
9 |
|
->where(['in', 'crmid', $missing]); |
136
|
9 |
|
$dataReader = $query->createCommand()->query(); |
137
|
8 |
|
while ($row = $dataReader->read()) { |
138
|
8 |
|
$row['deleted'] = (int) $row['deleted']; |
139
|
8 |
|
$row['smownerid'] = (int) $row['smownerid']; |
140
|
8 |
|
$row['smcreatorid'] = (int) $row['smcreatorid']; |
141
|
8 |
|
$row['crmid'] = (int) $row['crmid']; |
142
|
8 |
|
$row['private'] = (int) $row['private']; |
143
|
|
|
self::$crmRecordIdMetadataCache[$row['crmid']] = $row; |
144
|
|
|
} |
145
|
26 |
|
} |
146
|
26 |
|
$result = []; |
147
|
26 |
|
foreach ($ids as $id) { |
148
|
19 |
|
if (isset(self::$crmRecordIdMetadataCache[$id])) { |
149
|
|
|
$result[$id] = self::$crmRecordIdMetadataCache[$id]; |
150
|
8 |
|
} else { |
151
|
|
|
$result[$id] = null; |
152
|
|
|
} |
153
|
26 |
|
} |
154
|
|
|
return $multimode ? $result : array_shift($result); |
155
|
|
|
} |
156
|
1 |
|
|
157
|
|
|
public static function getCRMRecordLabel($id, $default = '') |
158
|
1 |
|
{ |
159
|
|
|
$label = \App\Record::getLabel($id); |
160
|
1 |
|
|
161
|
|
|
return empty($label) ? $default : $label; |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* Function to gets mudule field ID. |
166
|
|
|
* |
167
|
|
|
* @param int|string $moduleId |
168
|
|
|
* @param int|string $mixed |
169
|
|
|
* @param bool $onlyactive |
170
|
|
|
* |
171
|
5821 |
|
* @return bool|int |
172
|
|
|
*/ |
173
|
5821 |
|
public static function getModuleFieldId($moduleId, $mixed, $onlyactive = true) |
174
|
2 |
|
{ |
175
|
|
|
$field = \App\Field::getFieldInfo($mixed, $moduleId); |
176
|
5821 |
|
|
177
|
5821 |
|
if ($field && $onlyactive && ('0' !== $field['presence'] && '2' !== $field['presence'])) { |
178
|
49 |
|
$field = null; |
179
|
49 |
|
} |
180
|
49 |
|
return $field ? $field['fieldid'] : false; |
181
|
49 |
|
} |
182
|
49 |
|
|
183
|
49 |
|
// Utility |
184
|
49 |
|
public static function formatDecimal($value) |
185
|
49 |
|
{ |
186
|
|
|
$fld_value = explode('.', $value); |
187
|
49 |
|
if (!empty($fld_value[1])) { |
188
|
49 |
|
$fld_value = rtrim($value, '0'); |
189
|
|
|
$value = rtrim($fld_value, '.'); |
190
|
5821 |
|
} |
191
|
1 |
|
return $value; |
192
|
|
|
} |
193
|
5821 |
|
|
194
|
|
|
public static function fromHtmlPopup($string, $encode = true) |
195
|
|
|
{ |
196
|
|
|
$popup_toHtml = [ |
197
|
|
|
'"' => '"', |
198
|
|
|
"'" => ''', |
199
|
|
|
]; |
200
|
|
|
if ($encode && \is_string($string)) { |
201
|
|
|
$string = addslashes(str_replace(array_values($popup_toHtml), array_keys($popup_toHtml), $string)); |
202
|
|
|
} |
203
|
|
|
return $string; |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
public static function br2nl($str) |
207
|
|
|
{ |
208
|
|
|
$str = preg_replace("/(\r\n)/", '\\r\\n', $str); |
209
|
|
|
$str = preg_replace("/'/", ' ', $str); |
210
|
|
|
return preg_replace('/"/', ' ', $str); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
public static function suppressHTMLTags($string) |
214
|
|
|
{ |
215
|
|
|
return preg_replace(['/</', '/>/', '/"/'], ['<', '>', '"'], $string); |
216
|
1 |
|
} |
217
|
|
|
|
218
|
1 |
|
/** Function used to retrieve a single field value from database. |
219
|
1 |
|
* @param string $tableName - tablename from which we will retrieve the field value |
220
|
1 |
|
* @param string $fieldName - fieldname to which we want to get the value from database |
221
|
1 |
|
* @param string $idName - idname which is the name of the entity id in the table like, inoviceid, etc., |
222
|
|
|
* @param int $id - entity id |
223
|
1 |
|
* return mixed $fieldval - field value of the needed fieldname from database will be returned |
224
|
|
|
*/ |
225
|
|
|
public static function getSingleFieldValue($tableName, $fieldName, $idName, $id) |
226
|
|
|
{ |
227
|
|
|
return (new \App\Db\Query())->select([$fieldName])->from($tableName)->where([$idName => $id])->scalar(); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** function used to change the Type of Data for advanced filters in custom view and Reports. |
231
|
|
|
* * @param string $table_name - tablename value from field table |
232
|
|
|
* * @param string $column_nametable_name - columnname value from field table |
233
|
|
|
* * @param string $type_of_data - current type of data of the field. It is to return the same TypeofData |
234
|
|
|
* * if the field is not matched with the $new_field_details array. |
235
|
|
|
* * return string $type_of_data - If the string matched with the $new_field_details array then the Changed |
236
|
|
|
* * typeofdata will return, else the same typeofdata will return. |
237
|
|
|
* * |
238
|
|
|
* * EXAMPLE: If you have a field entry like this: |
239
|
|
|
* * |
240
|
|
|
* * fieldlabel | typeofdata | tablename | columnname | |
241
|
|
|
* * -------------------+------------+----------------------+------------------+ |
242
|
|
|
* * Potential Name | I~O | vtiger_quotes | potentialid | |
243
|
|
|
* * |
244
|
|
|
* * Then put an entry in $new_field_details like this: |
245
|
|
|
* * |
246
|
|
|
* * "vtiger_quotes:potentialid"=>"V", |
247
|
|
|
* * |
248
|
|
|
* * Now in customview and report's advance filter this field's criteria will be show like string. |
249
|
|
|
* @param mixed $column_name |
250
|
|
|
* */ |
251
|
|
|
public static function transformFieldTypeOfData($table_name, $column_name, $type_of_data) |
252
|
|
|
{ |
253
|
|
|
$field = $table_name . ':' . $column_name; |
254
|
|
|
//Add the field details in this array if you want to change the advance filter field details |
255
|
|
|
|
256
|
|
|
static $new_field_details = [ |
257
|
|
|
//Contacts Related Fields |
258
|
|
|
'vtiger_contactdetails:parentid' => 'V', |
259
|
|
|
'vtiger_contactsubdetails:birthday' => 'D', |
260
|
|
|
'vtiger_contactdetails:email' => 'V', |
261
|
|
|
'vtiger_contactdetails:secondaryemail' => 'V', |
262
|
|
|
//Account Related Fields |
263
|
|
|
'vtiger_account:parentid' => 'V', |
264
|
|
|
'vtiger_account:email1' => 'V', |
265
|
|
|
'vtiger_account:email2' => 'V', |
266
|
|
|
//Lead Related Fields |
267
|
|
|
'vtiger_leaddetails:email' => 'V', |
268
|
|
|
'vtiger_leaddetails:secondaryemail' => 'V', |
269
|
|
|
//Documents Related Fields |
270
|
|
|
'vtiger_senotesrel:crmid' => 'V', |
271
|
|
|
//HelpDesk Related Fields |
272
|
|
|
'vtiger_troubletickets:parent_id' => 'V', |
273
|
|
|
'vtiger_troubletickets:product_id' => 'V', |
274
|
|
|
//Product Related Fields |
275
|
|
|
'vtiger_products:discontinued' => 'C', |
276
|
|
|
'vtiger_products:vendor_id' => 'V', |
277
|
|
|
'vtiger_products:parentid' => 'V', |
278
|
|
|
//Faq Related Fields |
279
|
|
|
'vtiger_faq:product_id' => 'V', |
280
|
|
|
//Vendor Related Fields |
281
|
|
|
'vtiger_vendor:email' => 'V', |
282
|
|
|
//Campaign Related Fields |
283
|
|
|
'vtiger_campaign:product_id' => 'V', |
284
|
14 |
|
//Related List Entries(For Report Module) |
285
|
|
|
'vtiger_activityproductrel:activityid' => 'V', |
286
|
14 |
|
'vtiger_activityproductrel:productid' => 'V', |
287
|
|
|
'vtiger_campaign_records:campaignid' => 'V', |
288
|
|
|
'vtiger_campaign_records:crmid' => 'V', |
289
|
14 |
|
'vtiger_pricebookproductrel:pricebookid' => 'V', |
290
|
|
|
'vtiger_pricebookproductrel:productid' => 'V', |
291
|
|
|
'vtiger_senotesrel:crmid' => 'V', |
292
|
|
|
'vtiger_senotesrel:notesid' => 'V', |
293
|
|
|
'vtiger_seproductsrel:crmid' => 'V', |
294
|
|
|
'vtiger_seproductsrel:productid' => 'V', |
295
|
|
|
'vtiger_pricebook:currency_id' => 'V', |
296
|
|
|
]; |
297
|
|
|
|
298
|
|
|
//If the Fields details does not match with the array, then we return the same typeofdata |
299
|
|
|
if (isset($new_field_details[$field])) { |
300
|
|
|
$type_of_data = $new_field_details[$field]; |
301
|
|
|
} |
302
|
|
|
return $type_of_data; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
public static function getArrayFromValue($values) |
306
|
|
|
{ |
307
|
|
|
if (\is_array($values)) { |
308
|
|
|
return $values; |
309
|
|
|
} |
310
|
|
|
if ('' === $values) { |
311
|
|
|
return []; |
312
|
|
|
} |
313
|
|
|
if (false === strpos($values, ',')) { |
314
|
|
|
$array[] = $values; |
|
|
|
|
315
|
|
|
} else { |
316
|
|
|
$array = explode(',', $values); |
317
|
|
|
} |
318
|
|
|
return $array; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
public static function throwNewException($e, $die = true, $messageHeader = 'LBL_ERROR') |
322
|
|
|
{ |
323
|
|
|
if (!headers_sent() && \App\Config::security('cspHeaderActive')) { |
324
|
|
|
header("content-security-policy: default-src 'self' 'nonce-" . \App\Session::get('CSP_TOKEN') . "'; object-src 'none';base-uri 'self'; frame-ancestors 'self';"); |
|
|
|
|
325
|
|
|
} |
326
|
|
|
$message = \is_object($e) ? $e->getMessage() : $e; |
327
|
|
|
$code = 500; |
328
|
|
|
if (!\is_array($message)) { |
329
|
|
|
if (false === strpos($message, '||')) { |
330
|
|
|
$message = \App\Language::translateSingleMod($message, 'Other.Exceptions'); |
331
|
|
|
} else { |
332
|
14 |
|
$params = explode('||', $message); |
333
|
6 |
|
$label = \App\Language::translateSingleMod(array_shift($params), 'Other.Exceptions'); |
334
|
|
|
$params = array_pad($params, substr_count($label, '%'), ''); |
335
|
14 |
|
$message = \call_user_func_array('vsprintf', [$label, $params]); |
336
|
|
|
} |
337
|
|
|
} |
338
|
|
|
if ('API' === \App\Process::$requestMode) { |
339
|
|
|
throw new \App\Exceptions\ApiException($message, 401); |
340
|
|
|
} |
341
|
|
|
if (\App\Request::_isAjax() && \App\Request::_isJSON()) { |
|
|
|
|
342
|
|
|
$response = new \Vtiger_Response(); |
343
|
|
|
$response->setEmitType(\Vtiger_Response::$EMIT_JSON); |
344
|
|
|
|
345
|
|
|
if (\is_object($e)) { |
346
|
|
|
$response->setException($e); |
347
|
|
|
} else { |
348
|
|
|
$trace = ''; |
349
|
|
|
if (\App\Config::debug('DISPLAY_EXCEPTION_BACKTRACE') && \is_object($e)) { |
350
|
|
|
$trace = str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', "->{$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"); |
351
|
|
|
} |
352
|
|
|
$response->setError($code, $message, $trace); |
353
|
|
|
} |
354
|
|
|
$response->emit(); |
355
|
|
|
} else { |
356
|
|
|
if (\PHP_SAPI !== 'cli') { |
357
|
|
|
if (\App\Config::debug('DISPLAY_EXCEPTION_BACKTRACE') && \is_object($e)) { |
358
|
|
|
$message = [ |
359
|
|
|
'message' => $message, |
360
|
|
|
'trace' => str_replace(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR, '', "-> {$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}"), |
361
|
|
|
]; |
362
|
|
|
$code = $e->getCode(); |
363
|
|
|
} |
364
|
|
|
http_response_code($code); |
365
|
|
|
$viewer = new \Vtiger_Viewer(); |
366
|
|
|
$viewer->assign('MESSAGE', \Config\Debug::$EXCEPTION_ERROR_TO_SHOW ? $message : \App\Language::translate('ERR_OCCURRED_ERROR')); |
367
|
|
|
$viewer->assign('MESSAGE_EXPANDED', \is_array($message)); |
368
|
|
|
$viewer->assign('HEADER_MESSAGE', \App\Language::translate($messageHeader)); |
369
|
|
|
$viewer->view('Exceptions/ExceptionError.tpl', 'Vtiger'); |
370
|
|
|
} else { |
371
|
|
|
echo(\Config\Debug::$EXCEPTION_ERROR_TO_SHOW ? $message : \App\Language::translate('ERR_OCCURRED_ERROR')) . PHP_EOL; |
|
|
|
|
372
|
|
|
} |
373
|
|
|
} |
374
|
|
|
if ($die) { |
375
|
|
|
trigger_error(print_r($message, true), E_USER_ERROR); |
376
|
|
|
if (\is_object($message)) { |
377
|
|
|
throw new $message(); |
378
|
|
|
} |
379
|
|
|
if (\is_array($message)) { |
380
|
|
|
throw new \App\Exceptions\AppException($message['message']); |
381
|
|
|
} |
382
|
|
|
throw new \App\Exceptions\AppException($message); |
383
|
|
|
} |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
/** |
387
|
|
|
* Get html rr plain text. |
388
|
|
|
* |
389
|
|
|
* @param string $content |
390
|
|
|
* |
391
|
|
|
* @return string |
392
|
|
|
*/ |
393
|
|
|
public static function getHtmlOrPlainText(string $content) |
394
|
|
|
{ |
395
|
|
|
if (\App\Utils::isHtml($content)) { |
396
|
|
|
$content = \App\Purifier::decodeHtml($content); |
397
|
|
|
} else { |
398
|
|
|
$content = nl2br($content); |
399
|
|
|
} |
400
|
|
|
return $content; |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
/** |
404
|
|
|
* Function to delete files and dirs. |
405
|
|
|
* |
406
|
|
|
* @param string $src |
407
|
|
|
* @param bool $outsideRoot |
408
|
|
|
*/ |
409
|
|
|
public static function recurseDelete($src, $outsideRoot = false): int |
410
|
|
|
{ |
411
|
|
|
$rootDir = ($outsideRoot || 0 === strpos($src, ROOT_DIRECTORY)) ? '' : ROOT_DIRECTORY . \DIRECTORY_SEPARATOR; |
412
|
|
|
if (!file_exists($rootDir . $src)) { |
413
|
|
|
return 0; |
414
|
|
|
} |
415
|
|
|
$i = 0; |
416
|
|
|
if (is_dir($rootDir . $src)) { |
417
|
|
|
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($rootDir . $src, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST) as $filename => $file) { |
418
|
|
|
if ($file->isFile()) { |
419
|
|
|
unlink($filename); |
420
|
|
|
++$i; |
421
|
|
|
} else { |
422
|
|
|
rmdir($filename); |
423
|
|
|
} |
424
|
|
|
} |
425
|
|
|
rmdir($rootDir . $src); |
426
|
|
|
} else { |
427
|
|
|
unlink($rootDir . $src); |
428
|
|
|
++$i; |
429
|
|
|
} |
430
|
|
|
return $i; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* The function copies files. |
435
|
|
|
* |
436
|
|
|
* @param string $src |
437
|
|
|
* @param string $dest |
438
|
|
|
* |
439
|
|
|
* @return int |
440
|
7 |
|
*/ |
441
|
|
|
public static function recurseCopy($src, $dest) |
442
|
7 |
|
{ |
443
|
7 |
|
$rootDir = ROOT_DIRECTORY . \DIRECTORY_SEPARATOR; |
444
|
2 |
|
if (!file_exists($rootDir . $src)) { |
445
|
|
|
return 0; |
446
|
6 |
|
} |
447
|
6 |
|
if ($dest && '/' !== substr($dest, -1) && '\\' !== substr($dest, -1)) { |
448
|
6 |
|
$dest = $dest . \DIRECTORY_SEPARATOR; |
449
|
6 |
|
} |
450
|
|
|
$i = 0; |
451
|
4 |
|
$dest = $rootDir . $dest; |
452
|
|
|
foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($src, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) { |
453
|
|
|
if ($item->isDir() && !file_exists($dest . $iterator->getSubPathName())) { |
|
|
|
|
454
|
6 |
|
mkdir($dest . $iterator->getSubPathName(), 0755); |
455
|
|
|
} elseif (!$item->isDir()) { |
456
|
|
|
copy($item->getRealPath(), $dest . $iterator->getSubPathName()); |
457
|
|
|
++$i; |
458
|
6 |
|
} |
459
|
|
|
} |
460
|
|
|
return $i; |
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
/** |
464
|
|
|
* Parse bytes. |
465
|
|
|
* |
466
|
|
|
* @param mixed $str |
467
|
|
|
* |
468
|
|
|
* @return float |
469
|
|
|
*/ |
470
|
|
|
public static function parseBytes($str): float |
471
|
|
|
{ |
472
|
|
|
if (is_numeric($str)) { |
473
|
|
|
return (float) $str; |
474
|
|
|
} |
475
|
|
|
$bytes = 0; |
476
|
|
|
if (preg_match('/([0-9\.]+)\s*([a-z]*)/i', $str, $regs)) { |
477
|
|
|
$bytes = (float) ($regs[1]); |
478
|
|
|
switch (strtolower($regs[2])) { |
479
|
|
|
case 'g': |
480
|
|
|
case 'gb': |
481
|
|
|
$bytes *= 1073741824; |
482
|
|
|
break; |
483
|
|
|
case 'm': |
484
|
|
|
case 'mb': |
485
|
|
|
$bytes *= 1048576; |
486
|
|
|
break; |
487
|
|
|
case 'k': |
488
|
|
|
case 'kb': |
489
|
|
|
$bytes *= 1024; |
490
|
13 |
|
break; |
491
|
|
|
default: |
492
|
13 |
|
break; |
493
|
13 |
|
} |
494
|
|
|
} |
495
|
|
|
return (float) $bytes; |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
/** |
499
|
|
|
* Show bytes. |
500
|
|
|
* |
501
|
|
|
* @param mixed $bytes |
502
|
|
|
* @param string|null $unit |
503
|
|
|
* |
504
|
|
|
* @return string |
505
|
|
|
*/ |
506
|
|
|
public static function showBytes($bytes, &$unit = null): string |
507
|
|
|
{ |
508
|
|
|
$bytes = self::parseBytes($bytes); |
509
|
|
|
if ($bytes >= 1073741824) { |
510
|
|
|
$unit = 'GB'; |
511
|
|
|
$gb = $bytes / 1073741824; |
512
|
|
|
$str = sprintf($gb >= 10 ? '%d ' : '%.2f ', $gb) . $unit; |
513
|
|
|
} elseif ($bytes >= 1048576) { |
514
|
|
|
$unit = 'MB'; |
515
|
|
|
$mb = $bytes / 1048576; |
516
|
|
|
$str = sprintf($mb >= 10 ? '%d ' : '%.2f ', $mb) . $unit; |
517
|
|
|
} elseif ($bytes >= 1024) { |
518
|
13 |
|
$unit = 'KB'; |
519
|
|
|
$str = sprintf('%d ', round($bytes / 1024)) . $unit; |
520
|
13 |
|
} else { |
521
|
13 |
|
$unit = 'B'; |
522
|
|
|
$str = sprintf('%d ', $bytes) . $unit; |
523
|
|
|
} |
524
|
|
|
return $str; |
525
|
13 |
|
} |
526
|
|
|
|
527
|
|
|
public static function getMinimizationOptions($type = 'js') |
528
|
|
|
{ |
529
|
13 |
|
switch ($type) { |
530
|
7 |
|
case 'js': |
531
|
7 |
|
$return = \App\Config::developer('MINIMIZE_JS'); |
532
|
|
|
break; |
533
|
7 |
|
case 'css': |
534
|
7 |
|
$return = \App\Config::developer('MINIMIZE_CSS'); |
535
|
|
|
break; |
536
|
13 |
|
default: |
537
|
|
|
break; |
538
|
|
|
} |
539
|
|
|
return $return; |
|
|
|
|
540
|
|
|
} |
541
|
|
|
|
542
|
|
|
/** |
543
|
|
|
* Checks if given date is working day, if not returns last working day. |
544
|
|
|
* |
545
|
|
|
* @param <Date> $date |
|
|
|
|
546
|
|
|
* |
547
|
|
|
* @return <Date> - last working y |
|
|
|
|
548
|
|
|
*/ |
549
|
|
|
public static function getLastWorkingDay($date) |
550
|
|
|
{ |
551
|
|
|
if (empty($date)) { |
552
|
|
|
$date = date('Y-m-d'); |
553
|
|
|
} |
554
|
|
|
$date = strtotime($date); |
555
|
|
|
if ('Sat' === date('D', $date)) { // switch to friday the day before |
556
|
|
|
$lastWorkingDay = date('Y-m-d', strtotime('-1 day', $date)); |
557
|
|
|
} elseif ('Sun' === date('D', $date)) { // switch to friday two days before |
558
|
|
|
$lastWorkingDay = date('Y-m-d', strtotime('-2 day', $date)); |
559
|
|
|
} else { |
560
|
|
|
$lastWorkingDay = date('Y-m-d', $date); |
561
|
|
|
} |
562
|
|
|
return $lastWorkingDay; |
563
|
|
|
} |
564
|
|
|
|
565
|
|
|
/** |
566
|
|
|
* Function that returns conversion info from default system currency to chosen one. |
567
|
|
|
* |
568
|
|
|
* @param <Integer> $currencyId - id of currency for which we want to retrieve conversion rate to default currency |
|
|
|
|
569
|
|
|
* @param <Date> $date - date of exchange rates, if empty then rate from yesterday |
570
|
|
|
* |
571
|
|
|
* @return <Array> - array containing: |
|
|
|
|
572
|
|
|
* date - date of rate |
573
|
1 |
|
* value - conversion 1 default currency -> $currencyId |
574
|
|
|
* conversion - 1 $currencyId -> default currency |
575
|
1 |
|
*/ |
576
|
|
|
public static function getConversionRateInfo($currencyId, $date = '') |
577
|
|
|
{ |
578
|
1 |
|
$defaultCurrencyId = \App\Fields\Currency::getDefault()['id']; |
579
|
1 |
|
$info = []; |
580
|
|
|
if (empty($date)) { |
581
|
1 |
|
$yesterday = date('Y-m-d', strtotime('-1 day')); |
582
|
|
|
$date = self::getLastWorkingDay($yesterday); |
583
|
|
|
} |
584
|
1 |
|
$info['date'] = $date; |
585
|
|
|
if ($currencyId == $defaultCurrencyId) { |
586
|
1 |
|
$info['value'] = 1.0; |
587
|
|
|
$info['conversion'] = 1.0; |
588
|
|
|
} else { |
589
|
2 |
|
$value = \Settings_CurrencyUpdate_Module_Model::getCleanInstance()->getCRMConversionRate($currencyId, $defaultCurrencyId, $date); |
590
|
|
|
$info['value'] = empty($value) ? 1.0 : round($value, 5); |
591
|
|
|
$info['conversion'] = empty($value) ? 1.0 : round(1 / $value, 5); |
592
|
2 |
|
} |
593
|
|
|
return $info; |
594
|
|
|
} |
595
|
2 |
|
|
596
|
|
|
/** |
597
|
|
|
* Getting parameters from URL. |
598
|
|
|
* |
599
|
|
|
* @param string|null $url |
600
|
|
|
* |
601
|
|
|
* @return array |
602
|
|
|
*/ |
603
|
|
|
public static function getQueryParams($url): array |
604
|
|
|
{ |
605
|
|
|
$queryParams = []; |
606
|
|
|
if (!empty($url) && $queryStr = parse_url(htmlspecialchars_decode($url), PHP_URL_QUERY)) { |
607
|
|
|
parse_str($queryStr, $queryParams); |
608
|
|
|
} |
609
|
|
|
|
610
|
|
|
return $queryParams; |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
public static function arrayDiffAssocRecursive($array1, $array2) |
614
|
|
|
{ |
615
|
|
|
$difference = []; |
616
|
|
|
foreach ($array1 as $key => $value) { |
617
|
|
|
if (\is_array($value)) { |
618
|
|
|
if (!isset($array2[$key]) || !\is_array($array2[$key])) { |
619
|
|
|
$difference[$key] = $value; |
620
|
|
|
} else { |
621
|
|
|
$newDiff = self::arrayDiffAssocRecursive($value, $array2[$key]); |
622
|
|
|
if (!empty($newDiff)) { |
623
|
|
|
$difference[$key] = $newDiff; |
624
|
|
|
} |
625
|
|
|
} |
626
|
|
|
} elseif (!\array_key_exists($key, $array2) || $array2[$key] !== $value) { |
627
|
|
|
$difference[$key] = $value; |
628
|
|
|
} |
629
|
|
|
} |
630
|
|
|
return $difference; |
631
|
|
|
} |
632
|
|
|
} |
633
|
|
|
|