Issues (806)

lib/midcom/helper/misc.php (3 issues)

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 530
    public static function parse_config($data, string $path) : array
44
    {
45
        try {
46 530
            return eval("return [{$data}\n];");
0 ignored issues
show
The use of eval() is discouraged.
Loading history...
47
        } catch (ParseError $e) {
0 ignored issues
show
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...
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 530
    public static function get_snippet_content_graceful(string $path)
65
    {
66 530
        static $cached_snippets = [];
67
68 530
        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 530
        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) {
0 ignored issues
show
The condition $data === null is always false.
Loading history...
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