Completed
Push — master ( 042f37...231ca8 )
by Andreas
27:43
created

midcom_helper_misc::include_element()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 20
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 5.1158

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 14
c 1
b 0
f 0
nc 8
nop 1
dl 0
loc 20
ccs 10
cts 12
cp 0.8333
crap 5.1158
rs 9.4888
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
/**
10
 * Miscellaneous helper functions
11
 *
12
 * @package midcom.helper
13
 */
14
class midcom_helper_misc
15
{
16
    /**
17
     *
18
     * @param integer $length
19
     * @param string $characters
20
     * @throws InvalidArgumentException
21
     * @return string
22
     */
23 13
    public static function random_string($length, $characters)
24
    {
25 13
        if ($length < 1) {
26
            throw new InvalidArgumentException('invalid length');
27
        }
28 13
        $size = strlen($characters) - 1;
29 13
        if ($size < 1) {
30
            throw new InvalidArgumentException('invalid characters');
31
        }
32 13
        $return = '';
33 13
        for ($i = 0; $i < $length; $i++) {
34 13
            $return .= $characters[random_int(0, $size)];
35
        }
36 13
        return $return;
37
    }
38
39
    /**
40
     * @param string $input
41
     * @return string
42
     */
43 27
    public static function urlize($input)
44
    {
45 27
        if (empty($input)) {
46 4
            return '';
47
        }
48 24
        return midgardmvc_helper_urlize::string($input, '-');
49
    }
50
51
    /**
52
     * Turn midcom config files into PHP arrays
53
     *
54
     * @param string $data The data to parse
55
     * @throws midcom_error
56
     * @return array The config in array format
57
     */
58 513
    public static function parse_config($data)
59
    {
60 513
        $data = eval("return [{$data}\n];");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
61 513
        if ($data === false) {
62
            throw new midcom_error("Failed to parse config data, see above for PHP errors.");
63
        }
64 513
        return $data;
65
    }
66
67
    /**
68
     * This helper function searches for a snippet either in the Filesystem
69
     * or in the database and returns its content or code-field, respectively.
70
     *
71
     * Prefix the snippet Path with 'file:' for retrieval of a file relative to
72
     * MIDCOM_ROOT; omit it to get the code field of a Snippet.
73
     *
74
     * Any error (files not found) will return null. If you want to trigger an error,
75
     * look for midcom_helper_misc::get_snippet_content.
76
     *
77
     * @param string $path  The URL to the snippet.
78
     * @return string       The content of the snippet/file.
79
     */
80 513
    public static function get_snippet_content_graceful($path)
81
    {
82 513
        static $cached_snippets = [];
83
84 513
        if (!array_key_exists($path, $cached_snippets)) {
85 61
            if (substr($path, 0, 5) == 'file:') {
86 45
                $cached_snippets[$path] = self::load_from_file($path);
87 20
            } elseif (substr($path, 0, 5) == 'conf:') {
88 20
                $cached_snippets[$path] = self::load(midcom::get()->config->get('midcom_config_basedir') . '/midcom' . substr($path, 5));
89
            } else {
90 17
                $cached_snippets[$path] = self::load_from_snippet($path);
91
            }
92
        }
93
94 513
        return $cached_snippets[$path];
95
    }
96
97 17
    private static function load_from_snippet($path)
98
    {
99 17
        $snippet = new midgard_snippet();
100 17
        if (!$snippet->get_by_path($path)) {
101 17
            return null;
102
        }
103
        if (isset(midcom::get()->cache->content)) {
104
            midcom::get()->cache->content->register($snippet->guid);
105
        }
106
        return $snippet->code;
107
    }
108
109 45
    private static function load_from_file($path)
110
    {
111 45
        $filename = MIDCOM_ROOT . substr($path, 5);
112 45
        if (!file_exists($filename)) {
113
            // try in src
114 2
            $filename = preg_replace('/\/lib\/?$/', '/src', MIDCOM_ROOT) . substr($path, 5);
115 2
            if (!file_exists($filename)) {
116
                //If we can't find the file in-tree, we look for out-of-tree components before giving up
117
                $filename = substr($path, 6);
118
                if (preg_match('|.+?/.+?/.+?/|', $filename)) {
119
                    $component_name = preg_replace('|(.+?)/(.+?)/(.+?)/.+|', '$1.$2.$3', $filename);
120
                    if (midcom::get()->componentloader->is_installed($component_name)) {
121
                        $filename = substr($filename, strlen($component_name));
122
                        $filename = midcom::get()->componentloader->path_to_snippetpath($component_name) . $filename;
123
                    }
124
                }
125
            }
126
        }
127 45
        return self::load($filename);
128
    }
129
130 61
    private static function load($filename)
131
    {
132 61
        if (!file_exists($filename)) {
133 20
            return null;
134
        }
135 45
        return file_get_contents($filename);
136
    }
137
138
    /**
139
     * This helper function searches for a snippet either in the Filesystem
140
     * or in the database and returns its content or code-field, respectively.
141
     *
142
     * Prefix the snippet Path with 'file:' for retrieval of a file relative to
143
     * MIDCOM_ROOT; omit it to get the code field of a Snippet.
144
     *
145
     * Any error (files not found) will raise a MidCOM Error. If you want a more
146
     * graceful behavior, look for midcom_helper_misc::get_snippet_content_graceful
147
     *
148
     * @param string $path    The URL to the snippet.
149
     * @return string        The content of the snippet/file.
150
     */
151 245
    public static function get_snippet_content($path)
152
    {
153 245
        $data = self::get_snippet_content_graceful($path);
154 245
        if ($data === null) {
0 ignored issues
show
introduced by
The condition $data === null is always false.
Loading history...
155
            throw new midcom_error("Could not load the contents of the snippet {$path}: Snippet does not exist.");
156
        }
157 245
        return $data;
158
    }
159
160
    /**
161
     * Preparse and include snippet
162
     *
163
     * @param string $path    The path of the snippet that should be included.
164
     * @return boolean Returns false if the snippet could not be loaded or true, if it was evaluated successfully.
165
     */
166
    public static function include_snippet_php($path)
167
    {
168
        $code = self::get_snippet_content_graceful($path);
169
        if (empty($code)) {
170
            debug_add("Could not find snippet {$path}: ", MIDCOM_LOG_ERROR);
171
            return false;
172
        }
173
        debug_add("Evaluating snippet {$path}.");
174
        eval('?>' . self::preparse($code));
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
175
        return true;
176
    }
177
178
    /**
179
     * This is a bit of a hack to allow &(); tags
180
     *
181
     * @param string $code The unprocessed code
182
     * @return string The processed code
183
     */
184 202
    public static function preparse($code)
185
    {
186
        // Get style elements
187 202
        $code = preg_replace_callback("/<\\(([a-zA-Z0-9 _-]+)\\)>/", [midcom_helper_misc::class, 'include_element'], $code);
188
        // Echo variables
189 202
        return preg_replace_callback("%&\(([^)]*)\);%i", [midcom_helper_formatter::class, 'convert_to_php'], $code);
190
    }
191
192
    /**
193
     * Include a theme element
194
     */
195 20
    public static function include_element($name)
196
    {
197 20
        if (is_array($name)) {
198 20
            $element = $name[1];
199
        } else {
200
            $element = $name;
201
        }
202
203
        switch ($element) {
204 20
            case 'title':
205 11
                return midcom::get()->config->get('midcom_site_title');
206 18
            case 'content':
207 18
                return '<?php midcom_core_context::get()->show(); ?>';
208
            default:
209 9
                $value = self::get_element_content($element);
210
211 9
                if (empty($value)) {
212
                    return '';
213
                }
214 9
                return preg_replace_callback("/<\\(([a-zA-Z0-9 _-]+)\\)>/", [midcom_helper_misc::class, 'include_element'], $value);
215
        }
216
    }
217
218
    /**
219
     * Find MIME type image for a document
220
     *
221
     * Used in midcom.helper.imagepopup, midgard.admin.asgard and org.openpsa.documents.
222
     *
223
     * @param string $mimetype  Document MIME type
224
     * @return string    Path to the icon
225
     */
226
    public static function get_mime_icon($mimetype)
227
    {
228
        $mime_fspath = MIDCOM_STATIC_ROOT . '/stock-icons/mime';
229
        $mime_urlpath = MIDCOM_STATIC_URL . '/stock-icons/mime';
230
        $mimetype_filename = str_replace('/', '-', $mimetype);
231
        if (!is_readable($mime_fspath)) {
232
            debug_add("Couldn't read directory {$mime_fspath}", MIDCOM_LOG_WARN);
233
        }
234
235
        $check_files = [];
236
        switch ($mimetype_filename) {
237
            case 'application-x-zip-compressed':
238
                $check_files[] = "gnome-application-zip.png";
239
                break;
240
            default:
241
                $check_files[] = "{$mimetype_filename}.png";
242
                $check_files[] = "gnome-{$mimetype_filename}.png";
243
                break;
244
        }
245
246
        // Return first match
247
        foreach ($check_files as $filename) {
248
            if (is_readable("{$mime_fspath}/{$filename}")) {
249
                return "{$mime_urlpath}/{$filename}";
250
            }
251
        }
252
        // Default icon if there is none for the MIME type
253
        return $mime_urlpath . '/gnome-unknown.png';
254
    }
255
256
    /**
257
     * Pretty print file sizes
258
     *
259
     * @param int $size  File size in bytes
260
     * @return string    Prettified file size
261
     */
262 7
    public static function filesize_to_string($size)
263
    {
264 7
        if ($size >= 1048576) {
265
            // More than a meg
266
            return sprintf("%01.1f", $size / 1048576) . " MB";
267
        }
268 7
        if ($size >= 1024) {
269
            // More than a kilo
270
            return sprintf("%01.1f", $size / 1024) . " KB";
271
        }
272 7
        return $size . " Bytes";
273
    }
274
275
    /**
276
     * Fix newline etc encoding issues in serialized data
277
     *
278
     * @param string $data The data to fix.
279
     * @return string $data with serializations fixed.
280
     */
281
    public static function fix_serialization($data)
282
    {
283
        //Skip on empty data
284
        if (empty($data)) {
285
            return $data;
286
        }
287
288
        $preg='/s:([0-9]+):"(.*?)";/ms';
289
        preg_match_all($preg, $data, $matches);
290
        $cache = [];
291
292
        foreach ($matches[0] as $k => $origFullStr) {
293
            $origLen = $matches[1][$k];
294
            $origStr = $matches[2][$k];
295
            $newLen = strlen($origStr);
296
            if ($newLen != $origLen) {
297
                $newFullStr = "s:$newLen:\"$origStr\";";
298
                //For performance we cache information on which strings have already been replaced
299
                if (!array_key_exists($origFullStr, $cache)) {
300
                    $data = str_replace($origFullStr, $newFullStr, $data);
301
                    $cache[$origFullStr] = true;
302
                }
303
            }
304
        }
305
306
        return $data;
307
    }
308
309
    /**
310
     * Returns the first instance of a given component on the site.
311
     *
312
     * @param string $component The component name
313
     * @return array NAP array of the first component instance found
314
     */
315 6
    public static function find_node_by_component($component)
316
    {
317 6
        static $cache = [];
318
319 6
        if (!array_key_exists($component, $cache)) {
320 2
            $cache[$component] = null;
321
322 2
            $nap = new midcom_helper_nav;
323 2
            $node_id = $nap->get_root_node();
324 2
            $root_node = $nap->get_node($node_id);
325
326 2
            if ($root_node[MIDCOM_NAV_COMPONENT] == $component) {
327
                $cache[$component] = $root_node;
328
            } else {
329 2
                $qb = midcom_db_topic::new_query_builder();
330 2
                $qb->add_constraint('component', '=', $component);
331 2
                $qb->add_constraint('name', '<>', '');
332 2
                $qb->add_constraint('up', 'INTREE', $node_id);
333 2
                $qb->set_limit(1);
334 2
                $topics = $qb->execute();
335
336 2
                if (count($topics) === 1) {
337 1
                    $cache[$component] = $nap->get_node($topics[0]->id);
338
                }
339
            }
340
        }
341
342 6
        return $cache[$component];
343
    }
344
345
    /**
346
     * Get the content of the element by the passed element name.
347
     * Tries to resolve path according to theme-name & page
348
     *
349
     * @param string $element_name
350
     */
351 202
    public static function get_element_content($element_name)
352
    {
353 202
        $theme = midcom::get()->config->get('theme');
354 202
        $path_array = explode('/', $theme);
355
356
        //get the page if there is one
357 202
        $page = midcom_connection::get_url('page_style');
358 202
        $substyle = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_SUBSTYLE);
359
        //check if we have elements for the sub-styles
360 202
        while (!empty($path_array)) {
361 202
            $theme_path = implode('/', $path_array);
362 202
            $candidates = [];
363 202
            if ($substyle) {
364 31
                $candidates[] = '/' . $substyle . '/' . $element_name;
365
            }
366 202
            if ($page) {
367
                $candidates[] = $page . '/' . $element_name;
368
            }
369 202
            $candidates[] = '/' . $element_name;
370
371 202
            foreach ($candidates as $candidate) {
372 202
                $filename = OPENPSA2_THEME_ROOT . $theme_path . '/style' . $candidate . '.php';
373 202
                if (file_exists($filename)) {
374 202
                    return file_get_contents($filename);
375
                }
376
            }
377
378
            //remove last theme part
379 202
            array_pop($path_array);
380
        }
381
382 202
        return false;
383
    }
384
}
385