Passed
Push — master ( f8d841...88b796 )
by Andreas
11:11
created

midcom_helper_misc::random_string()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.128

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 4
nop 2
dl 0
loc 14
ccs 8
cts 10
cp 0.8
crap 4.128
rs 9.9666
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 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 37
    public static function urlize(string $input) : string
35
    {
36 37
        $slugify = new Slugify;
37 37
        return $slugify->slugify($input);
38
    }
39
40
    /**
41
     * Turn midcom config files into PHP arrays
42
     */
43 524
    public static function parse_config($data, string $path) : array
44
    {
45
        try {
46 524
            return eval("return [{$data}\n];");
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
47
        } 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...
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 524
    public static function get_snippet_content_graceful(string $path)
65
    {
66 524
        static $cached_snippets = [];
67
68 524
        if (!array_key_exists($path, $cached_snippets)) {
69 64
            if (str_starts_with($path, 'file:')) {
70 45
                $cached_snippets[$path] = self::load_from_file($path);
71 22
            } elseif (str_starts_with($path, 'conf:')) {
72 22
                $cached_snippets[$path] = self::load(midcom::get()->config->get('midcom_config_basedir') . '/midcom' . substr($path, 5));
73
            } else {
74 18
                $cached_snippets[$path] = self::load_from_snippet($path);
75
            }
76
        }
77
78 524
        return $cached_snippets[$path];
79
    }
80
81 18
    private static function load_from_snippet(string $path) : ?string
82
    {
83 18
        $snippet = new midgard_snippet();
84 18
        if (!$snippet->get_by_path($path)) {
85 18
            return null;
86
        }
87
        midcom::get()->cache->content->register($snippet->guid);
88
        return $snippet->code;
89
    }
90
91 45
    private static function load_from_file(string $path)
92
    {
93 45
        $filename = MIDCOM_ROOT . substr($path, 5);
94 45
        if (!file_exists($filename)) {
95
            // try in src
96 2
            $filename = preg_replace('/\/lib\/?$/', '/src', MIDCOM_ROOT) . substr($path, 5);
97 2
            if (!file_exists($filename)) {
98
                //If we can't find the file in-tree, we look for out-of-tree components before giving up
99
                $filename = substr($path, 6);
100
                if (preg_match('|.+?/.+?/.+?/|', $filename)) {
101
                    $component_name = preg_replace('|(.+?)/(.+?)/(.+?)/.+|', '$1.$2.$3', $filename);
102
                    if (midcom::get()->componentloader->is_installed($component_name)) {
103
                        $filename = substr($filename, strlen($component_name));
104
                        $filename = midcom::get()->componentloader->path_to_snippetpath($component_name) . $filename;
105
                    }
106
                }
107
            }
108
        }
109 45
        return self::load($filename);
110
    }
111
112 64
    private static function load(string $filename)
113
    {
114 64
        if (!is_readable($filename)) {
115 22
            return null;
116
        }
117 45
        return file_get_contents($filename);
118
    }
119
120
    /**
121
     * This helper function searches for a snippet either in the Filesystem
122
     * or in the database and returns its content or code-field, respectively.
123
     *
124
     * Prefix the snippet Path with 'file:' for retrieval of a file relative to
125
     * MIDCOM_ROOT; omit it to get the code field of a Snippet.
126
     *
127
     * Any error (files not found) will raise a MidCOM Error. If you want a more
128
     * graceful behavior, look for midcom_helper_misc::get_snippet_content_graceful
129
     */
130 170
    public static function get_snippet_content(string $path) : string
131
    {
132 170
        $data = self::get_snippet_content_graceful($path);
133 170
        if ($data === null) {
0 ignored issues
show
introduced by
The condition $data === null is always false.
Loading history...
134
            throw new midcom_error("Could not load the contents of the snippet {$path}: Snippet does not exist.");
135
        }
136 170
        return $data;
137
    }
138
139
    /**
140
     * Find MIME type image for a document
141
     *
142
     * Used in midcom.helper.imagepopup, midgard.admin.asgard and org.openpsa.documents.
143
     *
144
     * @return string    Path to the icon
145
     */
146
    public static function get_mime_icon(string $mimetype) : string
147
    {
148
        $mime_fspath = MIDCOM_STATIC_ROOT . '/stock-icons/mime';
149
        $mime_urlpath = MIDCOM_STATIC_URL . '/stock-icons/mime';
150
        $mimetype_filename = str_replace('/', '-', $mimetype);
151
        if (!is_readable($mime_fspath)) {
152
            debug_add("Couldn't read directory {$mime_fspath}", MIDCOM_LOG_WARN);
153
        }
154
155
        if ($mimetype_filename == 'application-x-zip-compressed') {
156
            $filename = "gnome-application-zip.png";
157
        } else {
158
            $filename = "gnome-{$mimetype_filename}.png";
159
        }
160
        if (is_readable("{$mime_fspath}/{$filename}")) {
161
            return "{$mime_urlpath}/{$filename}";
162
        }
163
        // Default icon if there is none for the MIME type
164
        return $mime_urlpath . '/gnome-unknown.png';
165
    }
166
167
    /**
168
     * Pretty print file sizes
169
     *
170
     * @param int $size  File size in bytes
171
     */
172 8
    public static function filesize_to_string(int $size) : string
173
    {
174 8
        if ($size >= 1048576) {
175
            // More than a meg
176
            return sprintf("%01.1f", $size / 1048576) . " MB";
177
        }
178 8
        if ($size >= 1024) {
179
            // More than a kilo
180
            return sprintf("%01.1f", $size / 1024) . " KB";
181
        }
182 8
        return $size . " Bytes";
183
    }
184
185
    /**
186
     * Returns the first instance of a given component on the site.
187
     *
188
     * @return array NAP array of the first component instance found
189
     */
190 5
    public static function find_node_by_component(string $component) : ?array
191
    {
192 5
        static $cache = [];
193
194 5
        if (!array_key_exists($component, $cache)) {
195 1
            $cache[$component] = null;
196
197 1
            $nap = new midcom_helper_nav;
198 1
            $node_id = $nap->get_root_node();
199 1
            $root_node = $nap->get_node($node_id);
200
201 1
            if ($root_node[MIDCOM_NAV_COMPONENT] == $component) {
202
                $cache[$component] = $root_node;
203
            } else {
204 1
                $qb = midcom_db_topic::new_query_builder();
205 1
                $qb->add_constraint('component', '=', $component);
206 1
                $qb->add_constraint('name', '<>', '');
207 1
                $qb->add_constraint('up', 'INTREE', $node_id);
208 1
                $qb->set_limit(1);
209 1
                $topics = $qb->execute();
210
211 1
                if (count($topics) === 1) {
212
                    $cache[$component] = $nap->get_node($topics[0]->id);
213
                }
214
            }
215
        }
216
217 5
        return $cache[$component];
218
    }
219
}
220