|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* @package midcom.helper |
|
4
|
|
|
* @author The Midgard Project, http://www.midgard-project.org |
|
5
|
|
|
* @copyright The Midgard Project, http://www.midgard-project.org |
|
6
|
|
|
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License |
|
7
|
|
|
*/ |
|
8
|
|
|
|
|
9
|
|
|
use Cocur\Slugify\Slugify; |
|
10
|
|
|
|
|
11
|
|
|
/** |
|
12
|
|
|
* Miscellaneous helper functions |
|
13
|
|
|
* |
|
14
|
|
|
* @package midcom.helper |
|
15
|
|
|
*/ |
|
16
|
|
|
class midcom_helper_misc |
|
17
|
|
|
{ |
|
18
|
14 |
|
public static function random_string(int $length, string $characters) : string |
|
19
|
|
|
{ |
|
20
|
14 |
|
if ($length < 1) { |
|
21
|
|
|
throw new InvalidArgumentException('invalid length'); |
|
22
|
|
|
} |
|
23
|
14 |
|
$size = strlen($characters) - 1; |
|
24
|
14 |
|
if ($size < 1) { |
|
25
|
|
|
throw new InvalidArgumentException('invalid characters'); |
|
26
|
|
|
} |
|
27
|
14 |
|
$return = ''; |
|
28
|
14 |
|
for ($i = 0; $i < $length; $i++) { |
|
29
|
14 |
|
$return .= $characters[random_int(0, $size)]; |
|
30
|
|
|
} |
|
31
|
14 |
|
return $return; |
|
32
|
|
|
} |
|
33
|
|
|
|
|
34
|
36 |
|
public static function urlize(string $input) : string |
|
35
|
|
|
{ |
|
36
|
36 |
|
$slugify = new Slugify; |
|
37
|
36 |
|
return $slugify->slugify($input); |
|
38
|
|
|
} |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* Turn midcom config files into PHP arrays |
|
42
|
|
|
*/ |
|
43
|
529 |
|
public static function parse_config($data, string $path) : array |
|
44
|
|
|
{ |
|
45
|
|
|
try { |
|
46
|
529 |
|
return eval("return [{$data}\n];"); |
|
|
|
|
|
|
47
|
|
|
} catch (ParseError $e) { |
|
|
|
|
|
|
48
|
|
|
throw new midcom_error('Failed to parse config data: ' . $e->getMessage() . ' in ' . $path . ' line ' . $e->getLine()); |
|
49
|
|
|
} |
|
50
|
|
|
} |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* This helper function searches for a snippet either in the Filesystem |
|
54
|
|
|
* or in the database and returns its content or code-field, respectively. |
|
55
|
|
|
* |
|
56
|
|
|
* Prefix the snippet Path with 'file:' for retrieval of a file relative to |
|
57
|
|
|
* MIDCOM_ROOT; omit it to get the code field of a Snippet. |
|
58
|
|
|
* |
|
59
|
|
|
* Any error (files not found) will return null. If you want to trigger an error, |
|
60
|
|
|
* look for midcom_helper_misc::get_snippet_content. |
|
61
|
|
|
* |
|
62
|
|
|
* @return string The content of the snippet/file. |
|
63
|
|
|
*/ |
|
64
|
529 |
|
public static function get_snippet_content_graceful(string $path) |
|
65
|
|
|
{ |
|
66
|
529 |
|
static $cached_snippets = []; |
|
67
|
|
|
|
|
68
|
529 |
|
if (!array_key_exists($path, $cached_snippets)) { |
|
69
|
25 |
|
$cached_snippets[$path] = null; |
|
70
|
25 |
|
if (str_starts_with($path, 'file:') || str_starts_with($path, 'conf:')) { |
|
71
|
25 |
|
$filename = self::resolve_path($path); |
|
72
|
25 |
|
if (is_readable($filename)) { |
|
73
|
25 |
|
$cached_snippets[$path] = file_get_contents($filename); |
|
74
|
|
|
} |
|
75
|
|
|
} else { |
|
76
|
18 |
|
$snippet = new midgard_snippet(); |
|
77
|
18 |
|
if ($snippet->get_by_path($path)) { |
|
78
|
|
|
midcom::get()->cache->content->register($snippet->guid); |
|
79
|
|
|
$cached_snippets[$path] = $snippet->code; |
|
80
|
|
|
} |
|
81
|
|
|
} |
|
82
|
|
|
} |
|
83
|
|
|
|
|
84
|
529 |
|
return $cached_snippets[$path]; |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
190 |
|
public static function resolve_path(string $path) : string |
|
88
|
|
|
{ |
|
89
|
190 |
|
if (str_starts_with($path, 'conf:')) { |
|
90
|
22 |
|
return midcom::get()->config->get('midcom_config_basedir') . '/midcom' . substr($path, 5); |
|
91
|
|
|
} |
|
92
|
172 |
|
if (str_starts_with($path, 'file:')) { |
|
93
|
172 |
|
$filename = MIDCOM_ROOT . substr($path, 5); |
|
94
|
172 |
|
if (file_exists($filename)) { |
|
95
|
172 |
|
return $filename; |
|
96
|
|
|
} |
|
97
|
|
|
// try in src |
|
98
|
2 |
|
$filename = preg_replace('/\/lib\/?$/', '/src', MIDCOM_ROOT) . substr($path, 5); |
|
99
|
2 |
|
if (file_exists($filename)) { |
|
100
|
2 |
|
return $filename; |
|
101
|
|
|
} |
|
102
|
|
|
//If we can't find the file in-tree, we look for out-of-tree components before giving up |
|
103
|
|
|
$filename = substr($path, 6); |
|
104
|
|
|
if (preg_match('|.+?/.+?/.+?/|', $filename)) { |
|
105
|
|
|
$component_name = preg_replace('|(.+?)/(.+?)/(.+?)/.+|', '$1.$2.$3', $filename); |
|
106
|
|
|
if (midcom::get()->componentloader->is_installed($component_name)) { |
|
107
|
|
|
$filename = substr($filename, strlen($component_name)); |
|
108
|
|
|
return midcom::get()->componentloader->path_to_snippetpath($component_name) . $filename; |
|
109
|
|
|
} |
|
110
|
|
|
} |
|
111
|
|
|
} |
|
112
|
|
|
return $path; |
|
113
|
|
|
} |
|
114
|
|
|
|
|
115
|
|
|
/** |
|
116
|
|
|
* This helper function searches for a snippet either in the Filesystem |
|
117
|
|
|
* or in the database and returns its content or code-field, respectively. |
|
118
|
|
|
* |
|
119
|
|
|
* Prefix the snippet Path with 'file:' for retrieval of a file relative to |
|
120
|
|
|
* MIDCOM_ROOT; omit it to get the code field of a Snippet. |
|
121
|
|
|
* |
|
122
|
|
|
* Any error (files not found) will raise a MidCOM Error. If you want a more |
|
123
|
|
|
* graceful behavior, look for midcom_helper_misc::get_snippet_content_graceful |
|
124
|
|
|
*/ |
|
125
|
172 |
|
public static function load_snippet(string $path) : array |
|
126
|
|
|
{ |
|
127
|
172 |
|
$resolved_path = self::resolve_path($path); |
|
128
|
172 |
|
if (str_ends_with($resolved_path, '.php')) { |
|
129
|
170 |
|
return include $resolved_path; |
|
130
|
|
|
} |
|
131
|
2 |
|
$data = self::get_snippet_content_graceful($path); |
|
132
|
2 |
|
if ($data === null) { |
|
|
|
|
|
|
133
|
|
|
throw new midcom_error("Could not load the contents of the snippet {$path}: Snippet does not exist."); |
|
134
|
|
|
} |
|
135
|
2 |
|
return self::parse_config($data, $path); |
|
136
|
|
|
} |
|
137
|
|
|
|
|
138
|
|
|
/** |
|
139
|
|
|
* Find MIME type image for a document |
|
140
|
|
|
* |
|
141
|
|
|
* Used in midcom.helper.imagepopup, midgard.admin.asgard and org.openpsa.documents. |
|
142
|
|
|
* |
|
143
|
|
|
* @return string Path to the icon |
|
144
|
|
|
*/ |
|
145
|
|
|
public static function get_mime_icon(string $mimetype) : string |
|
146
|
|
|
{ |
|
147
|
|
|
$mime_fspath = MIDCOM_STATIC_ROOT . '/stock-icons/mime'; |
|
148
|
|
|
$mime_urlpath = MIDCOM_STATIC_URL . '/stock-icons/mime'; |
|
149
|
|
|
$mimetype_filename = str_replace('/', '-', $mimetype); |
|
150
|
|
|
if (!is_readable($mime_fspath)) { |
|
151
|
|
|
debug_add("Couldn't read directory {$mime_fspath}", MIDCOM_LOG_WARN); |
|
152
|
|
|
} |
|
153
|
|
|
|
|
154
|
|
|
if ($mimetype_filename == 'application-x-zip-compressed') { |
|
155
|
|
|
$filename = "gnome-application-zip.png"; |
|
156
|
|
|
} else { |
|
157
|
|
|
$filename = "gnome-{$mimetype_filename}.png"; |
|
158
|
|
|
} |
|
159
|
|
|
if (is_readable("{$mime_fspath}/{$filename}")) { |
|
160
|
|
|
return "{$mime_urlpath}/{$filename}"; |
|
161
|
|
|
} |
|
162
|
|
|
// Default icon if there is none for the MIME type |
|
163
|
|
|
return $mime_urlpath . '/gnome-unknown.png'; |
|
164
|
|
|
} |
|
165
|
|
|
|
|
166
|
|
|
/** |
|
167
|
|
|
* Pretty print file sizes |
|
168
|
|
|
* |
|
169
|
|
|
* @param int $size File size in bytes |
|
170
|
|
|
*/ |
|
171
|
8 |
|
public static function filesize_to_string(int $size) : string |
|
172
|
|
|
{ |
|
173
|
8 |
|
if ($size >= 1048576) { |
|
174
|
|
|
// More than a meg |
|
175
|
|
|
return sprintf("%01.1f", $size / 1048576) . " MB"; |
|
176
|
|
|
} |
|
177
|
8 |
|
if ($size >= 1024) { |
|
178
|
|
|
// More than a kilo |
|
179
|
|
|
return sprintf("%01.1f", $size / 1024) . " KB"; |
|
180
|
|
|
} |
|
181
|
8 |
|
return $size . " Bytes"; |
|
182
|
|
|
} |
|
183
|
|
|
|
|
184
|
|
|
/** |
|
185
|
|
|
* Returns the first instance of a given component on the site. |
|
186
|
|
|
* |
|
187
|
|
|
* @return array NAP array of the first component instance found |
|
188
|
|
|
*/ |
|
189
|
5 |
|
public static function find_node_by_component(string $component) : ?array |
|
190
|
|
|
{ |
|
191
|
5 |
|
static $cache = []; |
|
192
|
|
|
|
|
193
|
5 |
|
if (!array_key_exists($component, $cache)) { |
|
194
|
1 |
|
$cache[$component] = null; |
|
195
|
|
|
|
|
196
|
1 |
|
$nap = new midcom_helper_nav; |
|
197
|
1 |
|
$node_id = $nap->get_root_node(); |
|
198
|
1 |
|
$root_node = $nap->get_node($node_id); |
|
199
|
|
|
|
|
200
|
1 |
|
if ($root_node[MIDCOM_NAV_COMPONENT] == $component) { |
|
201
|
|
|
$cache[$component] = $root_node; |
|
202
|
|
|
} else { |
|
203
|
1 |
|
$qb = midcom_db_topic::new_query_builder(); |
|
204
|
1 |
|
$qb->add_constraint('component', '=', $component); |
|
205
|
1 |
|
$qb->add_constraint('name', '<>', ''); |
|
206
|
1 |
|
$qb->add_constraint('up', 'INTREE', $node_id); |
|
207
|
1 |
|
$qb->set_limit(1); |
|
208
|
1 |
|
$topics = $qb->execute(); |
|
209
|
|
|
|
|
210
|
1 |
|
if (count($topics) === 1) { |
|
211
|
|
|
$cache[$component] = $nap->get_node($topics[0]->id); |
|
212
|
|
|
} |
|
213
|
|
|
} |
|
214
|
|
|
} |
|
215
|
|
|
|
|
216
|
5 |
|
return $cache[$component]; |
|
217
|
|
|
} |
|
218
|
|
|
} |
|
219
|
|
|
|