Passed
Push — master ( 412da6...388458 )
by Andreas
22:53
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 513
        $data = eval("return [{$data}\n];");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
57 513
        if ($data === false) {
58
            throw new midcom_error("Failed to parse config data, see above for PHP errors.");
59
        }
60 513
        return $data;
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
     * This is a bit of a hack to allow &(); tags
157
     *
158
     * @param string $code The unprocessed code
159
     */
160 201
    public static function preparse($code) : string
161
    {
162
        // Get style elements
163 201
        $code = preg_replace_callback("/<\\(([a-zA-Z0-9 _-]+)\\)>/", [midcom_helper_misc::class, 'include_element'], $code);
164
        // Echo variables
165 201
        return preg_replace_callback("%&\(([^)]*)\);%i", [midcom_helper_formatter::class, 'convert_to_php'], $code);
166
    }
167
168
    /**
169
     * Include a theme element
170
     */
171 20
    public static function include_element($name) : string
172
    {
173 20
        if (is_array($name)) {
174 20
            $element = $name[1];
175
        } else {
176
            $element = $name;
177
        }
178
179 20
        switch ($element) {
180 20
            case 'title':
181 10
                return midcom::get()->config->get('midcom_site_title');
182 19
            case 'content':
183 19
                return '<?php midcom_core_context::get()->show(); ?>';
184
            default:
185 9
                $value = self::get_element_content($element);
186
187 9
                if (empty($value)) {
188
                    return '';
189
                }
190 9
                return preg_replace_callback("/<\\(([a-zA-Z0-9 _-]+)\\)>/", [midcom_helper_misc::class, 'include_element'], $value);
191
        }
192
    }
193
194
    /**
195
     * Find MIME type image for a document
196
     *
197
     * Used in midcom.helper.imagepopup, midgard.admin.asgard and org.openpsa.documents.
198
     *
199
     * @param string $mimetype  Document MIME type
200
     * @return string    Path to the icon
201
     */
202
    public static function get_mime_icon($mimetype) : string
203
    {
204
        $mime_fspath = MIDCOM_STATIC_ROOT . '/stock-icons/mime';
205
        $mime_urlpath = MIDCOM_STATIC_URL . '/stock-icons/mime';
206
        $mimetype_filename = str_replace('/', '-', $mimetype);
207
        if (!is_readable($mime_fspath)) {
208
            debug_add("Couldn't read directory {$mime_fspath}", MIDCOM_LOG_WARN);
209
        }
210
211
        $check_files = [];
212
        switch ($mimetype_filename) {
213
            case 'application-x-zip-compressed':
214
                $check_files[] = "gnome-application-zip.png";
215
                break;
216
            default:
217
                $check_files[] = "{$mimetype_filename}.png";
218
                $check_files[] = "gnome-{$mimetype_filename}.png";
219
                break;
220
        }
221
222
        // Return first match
223
        foreach ($check_files as $filename) {
224
            if (is_readable("{$mime_fspath}/{$filename}")) {
225
                return "{$mime_urlpath}/{$filename}";
226
            }
227
        }
228
        // Default icon if there is none for the MIME type
229
        return $mime_urlpath . '/gnome-unknown.png';
230
    }
231
232
    /**
233
     * Pretty print file sizes
234
     *
235
     * @param int $size  File size in bytes
236
     */
237 7
    public static function filesize_to_string($size) : string
238
    {
239 7
        if ($size >= 1048576) {
240
            // More than a meg
241
            return sprintf("%01.1f", $size / 1048576) . " MB";
242
        }
243 7
        if ($size >= 1024) {
244
            // More than a kilo
245
            return sprintf("%01.1f", $size / 1024) . " KB";
246
        }
247 7
        return $size . " Bytes";
248
    }
249
250
    /**
251
     * Fix newline etc encoding issues in serialized data
252
     *
253
     * @param string $data The data to fix.
254
     * @return string $data with serializations fixed.
255
     */
256
    public static function fix_serialization($data)
257
    {
258
        //Skip on empty data
259
        if (empty($data)) {
260
            return $data;
261
        }
262
263
        $preg='/s:([0-9]+):"(.*?)";/ms';
264
        preg_match_all($preg, $data, $matches);
265
        $cache = [];
266
267
        foreach ($matches[0] as $k => $origFullStr) {
268
            $origLen = $matches[1][$k];
269
            $origStr = $matches[2][$k];
270
            $newLen = strlen($origStr);
271
            if ($newLen != $origLen) {
272
                $newFullStr = "s:$newLen:\"$origStr\";";
273
                //For performance we cache information on which strings have already been replaced
274
                if (!array_key_exists($origFullStr, $cache)) {
275
                    $data = str_replace($origFullStr, $newFullStr, $data);
276
                    $cache[$origFullStr] = true;
277
                }
278
            }
279
        }
280
281
        return $data;
282
    }
283
284
    /**
285
     * Returns the first instance of a given component on the site.
286
     *
287
     * @param string $component The component name
288
     * @return array NAP array of the first component instance found
289
     */
290 6
    public static function find_node_by_component($component)
291
    {
292 6
        static $cache = [];
293
294 6
        if (!array_key_exists($component, $cache)) {
295 2
            $cache[$component] = null;
296
297 2
            $nap = new midcom_helper_nav;
298 2
            $node_id = $nap->get_root_node();
299 2
            $root_node = $nap->get_node($node_id);
300
301 2
            if ($root_node[MIDCOM_NAV_COMPONENT] == $component) {
302
                $cache[$component] = $root_node;
303
            } else {
304 2
                $qb = midcom_db_topic::new_query_builder();
305 2
                $qb->add_constraint('component', '=', $component);
306 2
                $qb->add_constraint('name', '<>', '');
307 2
                $qb->add_constraint('up', 'INTREE', $node_id);
308 2
                $qb->set_limit(1);
309 2
                $topics = $qb->execute();
310
311 2
                if (count($topics) === 1) {
312 1
                    $cache[$component] = $nap->get_node($topics[0]->id);
313
                }
314
            }
315
        }
316
317 6
        return $cache[$component];
318
    }
319
320
    /**
321
     * Get the content of the element by the passed element name.
322
     * Tries to resolve path according to theme-name & page
323
     *
324
     * @param string $element_name
325
     */
326 202
    public static function get_element_content($element_name)
327
    {
328 202
        $theme = midcom::get()->config->get('theme');
329 202
        $path_array = explode('/', $theme);
330
331
        //get the page if there is one
332 202
        $page = midcom_connection::get_url('page_style');
333 202
        $substyle = midcom_core_context::get()->get_key(MIDCOM_CONTEXT_SUBSTYLE);
334
        //check if we have elements for the sub-styles
335 202
        while (!empty($path_array)) {
336 202
            $theme_path = implode('/', $path_array);
337 202
            $candidates = [];
338 202
            if ($substyle) {
339 31
                $candidates[] = '/' . $substyle . '/' . $element_name;
340
            }
341 202
            if ($page) {
342
                $candidates[] = $page . '/' . $element_name;
343
            }
344 202
            $candidates[] = '/' . $element_name;
345
346 202
            foreach ($candidates as $candidate) {
347 202
                $filename = OPENPSA2_THEME_ROOT . $theme_path . '/style' . $candidate . '.php';
348 202
                if (file_exists($filename)) {
349 10
                    return file_get_contents($filename);
350
                }
351
            }
352
353
            //remove last theme part
354 202
            array_pop($path_array);
355
        }
356
357 202
        return false;
358
    }
359
}
360