Passed
Push — master ( 1dad25...20642a )
by Andreas
24:28
created

midcom_helper_misc::get_snippet_content()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
ccs 4
cts 5
cp 0.8
crap 2.032
rs 10
c 0
b 0
f 0
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
    /**
19
     * @param integer $length
20
     * @param string $characters
21
     * @throws InvalidArgumentException
22
     */
23 13
    public static function random_string($length, $characters) : string
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
     */
42 27
    public static function urlize($input) : string
43
    {
44 27
        $slugify = new Slugify;
45 27
        return $slugify->slugify($input);
46
    }
47
48
    /**
49
     * Turn midcom config files into PHP arrays
50
     *
51
     * @param string $data The data to parse
52
     * @throws midcom_error
53
     */
54 513
    public static function parse_config($data) : array
55
    {
56
        try {
57 513
            return eval("return [{$data}\n];");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
58
        } catch (ParseError $e) {
0 ignored issues
show
Unused Code introduced by
catch (\ParseError $e) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
59
            throw new midcom_error('Failed to parse config data: ' . $e->getMessage() . ' in line ' . $e->getLine());
60
        }
61
    }
62
63
    /**
64
     * This helper function searches for a snippet either in the Filesystem
65
     * or in the database and returns its content or code-field, respectively.
66
     *
67
     * Prefix the snippet Path with 'file:' for retrieval of a file relative to
68
     * MIDCOM_ROOT; omit it to get the code field of a Snippet.
69
     *
70
     * Any error (files not found) will return null. If you want to trigger an error,
71
     * look for midcom_helper_misc::get_snippet_content.
72
     *
73
     * @param string $path  The URL to the snippet.
74
     * @return string       The content of the snippet/file.
75
     */
76 513
    public static function get_snippet_content_graceful($path)
77
    {
78 513
        static $cached_snippets = [];
79
80 513
        if (!array_key_exists($path, $cached_snippets)) {
81 63
            if (substr($path, 0, 5) == 'file:') {
82 46
                $cached_snippets[$path] = self::load_from_file($path);
83 22
            } elseif (substr($path, 0, 5) == 'conf:') {
84 22
                $cached_snippets[$path] = self::load(midcom::get()->config->get('midcom_config_basedir') . '/midcom' . substr($path, 5));
85
            } else {
86 17
                $cached_snippets[$path] = self::load_from_snippet($path);
87
            }
88
        }
89
90 513
        return $cached_snippets[$path];
91
    }
92
93 17
    private static function load_from_snippet(string $path)
94
    {
95 17
        $snippet = new midgard_snippet();
96 17
        if (!$snippet->get_by_path($path)) {
97 17
            return null;
98
        }
99
        if (isset(midcom::get()->cache->content)) {
100
            midcom::get()->cache->content->register($snippet->guid);
101
        }
102
        return $snippet->code;
103
    }
104
105 46
    private static function load_from_file(string $path)
106
    {
107 46
        $filename = MIDCOM_ROOT . substr($path, 5);
108 46
        if (!file_exists($filename)) {
109
            // try in src
110 2
            $filename = preg_replace('/\/lib\/?$/', '/src', MIDCOM_ROOT) . substr($path, 5);
111 2
            if (!file_exists($filename)) {
112
                //If we can't find the file in-tree, we look for out-of-tree components before giving up
113
                $filename = substr($path, 6);
114
                if (preg_match('|.+?/.+?/.+?/|', $filename)) {
115
                    $component_name = preg_replace('|(.+?)/(.+?)/(.+?)/.+|', '$1.$2.$3', $filename);
116
                    if (midcom::get()->componentloader->is_installed($component_name)) {
117
                        $filename = substr($filename, strlen($component_name));
118
                        $filename = midcom::get()->componentloader->path_to_snippetpath($component_name) . $filename;
119
                    }
120
                }
121
            }
122
        }
123 46
        return self::load($filename);
124
    }
125
126 63
    private static function load(string $filename)
127
    {
128 63
        if (!file_exists($filename)) {
129 22
            return null;
130
        }
131 46
        return file_get_contents($filename);
132
    }
133
134
    /**
135
     * This helper function searches for a snippet either in the Filesystem
136
     * or in the database and returns its content or code-field, respectively.
137
     *
138
     * Prefix the snippet Path with 'file:' for retrieval of a file relative to
139
     * MIDCOM_ROOT; omit it to get the code field of a Snippet.
140
     *
141
     * Any error (files not found) will raise a MidCOM Error. If you want a more
142
     * graceful behavior, look for midcom_helper_misc::get_snippet_content_graceful
143
     *
144
     * @param string $path    The URL to the snippet.
145
     */
146 247
    public static function get_snippet_content($path) : string
147
    {
148 247
        $data = self::get_snippet_content_graceful($path);
149 247
        if ($data === null) {
0 ignored issues
show
introduced by
The condition $data === null is always false.
Loading history...
150
            throw new midcom_error("Could not load the contents of the snippet {$path}: Snippet does not exist.");
151
        }
152 247
        return $data;
153
    }
154
155
    /**
156
     * Include a theme element
157
     */
158 20
    public static function include_element($name) : string
159
    {
160 20
        if (is_array($name)) {
161 20
            $element = $name[1];
162
        } else {
163
            $element = $name;
164
        }
165
166 20
        switch ($element) {
167 20
            case 'title':
168 10
                return midcom::get()->config->get('midcom_site_title');
169 19
            case 'content':
170 19
                return '<?php midcom_core_context::get()->show(); ?>';
171
            default:
172 9
                $value = self::get_element_content($element);
173
174 9
                if (empty($value)) {
175
                    return '';
176
                }
177 9
                return preg_replace_callback("/<\\(([a-zA-Z0-9 _-]+)\\)>/", [midcom_helper_misc::class, 'include_element'], $value);
178
        }
179
    }
180
181
    /**
182
     * Find MIME type image for a document
183
     *
184
     * Used in midcom.helper.imagepopup, midgard.admin.asgard and org.openpsa.documents.
185
     *
186
     * @param string $mimetype  Document MIME type
187
     * @return string    Path to the icon
188
     */
189
    public static function get_mime_icon($mimetype) : string
190
    {
191
        $mime_fspath = MIDCOM_STATIC_ROOT . '/stock-icons/mime';
192
        $mime_urlpath = MIDCOM_STATIC_URL . '/stock-icons/mime';
193
        $mimetype_filename = str_replace('/', '-', $mimetype);
194
        if (!is_readable($mime_fspath)) {
195
            debug_add("Couldn't read directory {$mime_fspath}", MIDCOM_LOG_WARN);
196
        }
197
198
        $check_files = [];
199
        switch ($mimetype_filename) {
200
            case 'application-x-zip-compressed':
201
                $check_files[] = "gnome-application-zip.png";
202
                break;
203
            default:
204
                $check_files[] = "{$mimetype_filename}.png";
205
                $check_files[] = "gnome-{$mimetype_filename}.png";
206
                break;
207
        }
208
209
        // Return first match
210
        foreach ($check_files as $filename) {
211
            if (is_readable("{$mime_fspath}/{$filename}")) {
212
                return "{$mime_urlpath}/{$filename}";
213
            }
214
        }
215
        // Default icon if there is none for the MIME type
216
        return $mime_urlpath . '/gnome-unknown.png';
217
    }
218
219
    /**
220
     * Pretty print file sizes
221
     *
222
     * @param int $size  File size in bytes
223
     */
224 7
    public static function filesize_to_string($size) : string
225
    {
226 7
        if ($size >= 1048576) {
227
            // More than a meg
228
            return sprintf("%01.1f", $size / 1048576) . " MB";
229
        }
230 7
        if ($size >= 1024) {
231
            // More than a kilo
232
            return sprintf("%01.1f", $size / 1024) . " KB";
233
        }
234 7
        return $size . " Bytes";
235
    }
236
237
    /**
238
     * Fix newline etc encoding issues in serialized data
239
     *
240
     * @param string $data The data to fix.
241
     * @return string $data with serializations fixed.
242
     */
243
    public static function fix_serialization($data)
244
    {
245
        //Skip on empty data
246
        if (empty($data)) {
247
            return $data;
248
        }
249
250
        $preg='/s:([0-9]+):"(.*?)";/ms';
251
        preg_match_all($preg, $data, $matches);
252
        $cache = [];
253
254
        foreach ($matches[0] as $k => $origFullStr) {
255
            $origLen = $matches[1][$k];
256
            $origStr = $matches[2][$k];
257
            $newLen = strlen($origStr);
258
            if ($newLen != $origLen) {
259
                $newFullStr = "s:$newLen:\"$origStr\";";
260
                //For performance we cache information on which strings have already been replaced
261
                if (!array_key_exists($origFullStr, $cache)) {
262
                    $data = str_replace($origFullStr, $newFullStr, $data);
263
                    $cache[$origFullStr] = true;
264
                }
265
            }
266
        }
267
268
        return $data;
269
    }
270
271
    /**
272
     * Returns the first instance of a given component on the site.
273
     *
274
     * @param string $component The component name
275
     * @return array NAP array of the first component instance found
276
     */
277 6
    public static function find_node_by_component($component)
278
    {
279 6
        static $cache = [];
280
281 6
        if (!array_key_exists($component, $cache)) {
282 2
            $cache[$component] = null;
283
284 2
            $nap = new midcom_helper_nav;
285 2
            $node_id = $nap->get_root_node();
286 2
            $root_node = $nap->get_node($node_id);
287
288 2
            if ($root_node[MIDCOM_NAV_COMPONENT] == $component) {
289
                $cache[$component] = $root_node;
290
            } else {
291 2
                $qb = midcom_db_topic::new_query_builder();
292 2
                $qb->add_constraint('component', '=', $component);
293 2
                $qb->add_constraint('name', '<>', '');
294 2
                $qb->add_constraint('up', 'INTREE', $node_id);
295 2
                $qb->set_limit(1);
296 2
                $topics = $qb->execute();
297
298 2
                if (count($topics) === 1) {
299 1
                    $cache[$component] = $nap->get_node($topics[0]->id);
300
                }
301
            }
302
        }
303
304 6
        return $cache[$component];
305
    }
306
307
    /**
308
     * Get the content of the element by the passed element name.
309
     * Tries to resolve path according to theme-name & page
310
     *
311
     * @param string $element_name
312
     */
313 202
    public static function get_element_content($element_name)
314
    {
315 202
        $theme = midcom::get()->config->get('theme');
316 202
        $path_array = explode('/', $theme);
317
318
        //get the page if there is one
319 202
        $page = midcom_connection::get_url('page_style');
320 202
        $substyle = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_SUBSTYLE);
321
        //check if we have elements for the sub-styles
322 202
        while (!empty($path_array)) {
323 202
            $theme_path = implode('/', $path_array);
324 202
            $candidates = [];
325 202
            if ($substyle) {
326 31
                $candidates[] = '/' . $substyle . '/' . $element_name;
327
            }
328 202
            if ($page) {
329
                $candidates[] = $page . '/' . $element_name;
330
            }
331 202
            $candidates[] = '/' . $element_name;
332
333 202
            foreach ($candidates as $candidate) {
334 202
                $filename = OPENPSA2_THEME_ROOT . $theme_path . '/style' . $candidate . '.php';
335 202
                if (file_exists($filename)) {
336 10
                    return file_get_contents($filename);
337
                }
338
            }
339
340
            //remove last theme part
341 202
            array_pop($path_array);
342
        }
343
344 202
        return false;
345
    }
346
}
347