Issues (762)

system/core/classes/classloader.php (6 issues)

1
<?php
2
3
/**
4
 * Copyright (c) 2018 Justin Kuenzel (jukusoft.com)
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
class ClassLoader {
20
21
    public static $classlist = array();
22
23
    public static $loadedClasses = 0;
24
25
    public static $namespace_autoloader = array();
26
27
    /**
28
     * initialize classloader (called only once / request)
29
     */
30
    public static function init () {
31
32
        //register autoloader
33
        spl_autoload_register('cms_autoloader');
34
35
        if (!file_exists(ROOT_PATH . "cache")) {
36
            mkdir(ROOT_PATH . "cache");
37
        }
38
39
        if (!file_exists(ROOT_PATH . "cache/classloader/classlist.php")) {
40
            self::rebuildCache();
41
        }
42
43
        require(ROOT_PATH . "cache/classloader/classlist.php");
44
        self::$classlist = $classlist;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $classlist seems to be never defined.
Loading history...
45
46
    }
47
48
    public static function rebuildCache () {
49
50
        require_once(ROOT_PATH . "system/core/classes/packages.php");
51
52
        if (file_exists(ROOT_PATH . "cache/classloader/classlist.php")) {
53
            @unlink(ROOT_PATH . "cache/classloader/classlist.php");
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

53
            /** @scrutinizer ignore-unhandled */ @unlink(ROOT_PATH . "cache/classloader/classlist.php");

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
54
        }
55
56
        if (!file_exists(ROOT_PATH . "cache/classloader")) {
57
            mkdir(ROOT_PATH . "cache/classloader");
58
        }
59
60
        $packages = Packages::listPackages();
61
62
        $classlist = array();
63
64
        foreach ($packages as $path) {
65
            $path = ROOT_PATH . "system/packages/" . $path . "/";
66
67
            if (file_exists($path . "classloader.xml")) {
68
                $xml = simplexml_load_file($path . "classloader.xml");
69
70
                foreach ($xml->xpath("//class") as $classname) {
71
                    $classlist[(String) $classname] = $path . "classes/" . strtolower((String) $classname) . ".php";
72
                }
73
            }
74
        }
75
76
        $handle = fopen(ROOT_PATH . "cache/classloader/classlist.php", "w");
77
78
        fwrite($handle, "<" . "?" . "php\r\n\r\n");
0 ignored issues
show
It seems like $handle can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
        fwrite(/** @scrutinizer ignore-type */ $handle, "<" . "?" . "php\r\n\r\n");
Loading history...
79
80
        fwrite($handle, "$" . "classlist = array(\r\n");
81
82
        foreach ($classlist as $classname=>$classpath) {
83
            fwrite($handle, "\t'" . $classname . "' => \"" . $classpath . "\",\r\n");
84
        }
85
86
        fwrite($handle, ");\r\n\r\n");
87
88
        fwrite($handle, "?" . ">");
89
90
        fclose($handle);
0 ignored issues
show
It seems like $handle can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
        fclose(/** @scrutinizer ignore-type */ $handle);
Loading history...
91
92
    }
93
94
    /**
95
     * add classloader for specific namespace prefix
96
     */
97
    public static function addLoader (string $prefix, callable $func) {
98
    	$prefix = strtolower($prefix);
99
    	self::$namespace_autoloader[$prefix] = $func;
100
	}
101
102
	public static function removeLoader (string $prefix) {
103
		$prefix = strtolower($prefix);
104
    	unset(self::$namespace_autoloader[$prefix]);
105
	}
106
107
}
108
109
/**
110
 * autoload function
111
 */
112
function cms_autoloader ($classname) {
113
114
    ClassLoader::$loadedClasses++;
115
116
    if (isset(Classloader::$classlist[$classname])) {
117
        require(Classloader::$classlist[$classname]);
118
        return null;
119
    }
120
121
    if (file_exists(ROOT_PATH . "system/core/classes/" . strtolower($classname) . ".php")) {
122
        require(ROOT_PATH . "system/core/classes/" . strtolower($classname) . ".php");
123
        return null;
124
    } else if (file_exists(ROOT_PATH . "system/core/exception/" . strtolower($classname) . ".php")) {
125
		require(ROOT_PATH . "system/core/exception/" . strtolower($classname) . ".php");
126
		return null;
127
	} else if (file_exists(ROOT_PATH . "system/core/driver/" . strtolower($classname) . ".php")) {
128
		require(ROOT_PATH . "system/core/driver/" . strtolower($classname) . ".php");
129
		return null;
130
	}
131
132
	//check, if class belongs to dwoo template engine
133
    if (PHPUtils::startsWith($classname, "Dwoo")) {
134
        if (class_exists("DwooAutoloader", true)) {
135
            DwooAutoloader::loadClass($classname);
136
            return;
137
        } else {
138
			echo "Could not load Dwoo template engine class " . $classname . "!";
139
        }
140
    }
141
142
    //check, if we have to use namespace classloading
143
	if (PHPUtils::containsStr($classname, "\\")) {
144
    	//we have to use namespace classloading
145
		if (PHPUtils::startsWith($classname, "\\")) {
146
			//use normal class loading
147
			$classname = substr($classname, 1);
148
		} else {
149
			$array = explode("\\", strtolower($classname));
150
151
			if ($array[0] === "plugin") {
152
				$array1 = array();
153
154
				for ($i = 2; $i < count($array); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
155
					$array1[] = $array[$i];
156
				}
157
158
				$file_name = implode("/", $array1);
159
160
				//load plugin class
161
				$path = PLUGIN_PATH . $array[1] . "/classes/" . $file_name . ".php";
162
163
				if (file_exists($path)) {
164
					require($path);
165
				} else {
166
					$expected_str = (DEBUG_MODE ? " (expected path: " . $path . ")" : "");
167
					echo "Could not load plugin-class with namespace " . $classname . $expected_str . "!";
168
				}
169
			} else {
170
				//check, if there is a classloader for this prefix
171
				if (isset(ClassLoader::$namespace_autoloader[$array[0]])) {
172
					//get function
173
					$func = ClassLoader::$namespace_autoloader[$array[0]];
174
175
					//call func
176
					$func($classname);
177
				} else {
178
					throw new IllegalStateException("Cannot load namespace class '" . $classname . "' with unknown prefix '" . $array[0] . "'!");
179
				}
180
			}
181
182
			return;
183
		}
184
	}
185
186
    $array = explode("_", strtolower($classname));
187
188
    if (sizeOf($array) == 3) {
189
190
        if ($array[0] == "plugin") {
191
            if (file_exists(ROOT_PATH . "plugins/" . strtolower($array[1]) . "/classes/" . strtolower($array[2]) . ".php")) {
192
                require(ROOT_PATH . "plugins/" . strtolower($array[1]) . "/classes/" . strtolower($array[2]) . ".php");
193
            } else {
194
                echo "Could not load plugin-class " . $classname . "!";
195
            }
196
        } else {
197
            if (file_exists(ROOT_PATH . "system/libs/smarty/sysplugins/" . strtolower($classname) . "php")) {
198
                require ROOT_PATH . "system/libs/smarty/sysplugins/" . strtolower($classname) . ".php";
199
            } else if ($classname == "Smarty") {
200
                require("system/libs/smarty/Smarty.class.php");
201
            } else {
202
                //echo "Could not (plugin) load class " . $classname . "!";
203
            }
204
        }
205
206
    } else if (sizeof($array) == 2) {
207
		if ($array[0] == "validator") {
208
			if (file_exists(ROOT_PATH . "system/core/validator/" . $array[1] . ".php")) {
209
				require(ROOT_PATH . "system/core/validator/" . $array[1] . ".php");
210
			} else {
211
				echo "Could not load validator class " . $classname . "!";
212
			}
213
		} else if ($array[0] == "datatype") {
214
			if (file_exists(ROOT_PATH . "system/core/datatype/" . $array[1] . ".php")) {
215
				require(ROOT_PATH . "system/core/datatype/" . $array[1] . ".php");
216
			} else {
217
				echo "Could not load datatype class " . $classname . "!";
218
			}
219
		} else if (strpos($classname, "Plugin")) {
220
			//dwoo tries several times to load a class - with and without namespace, so we hide this error message
221
		} else {
222
			echo "Could not load class " . $classname . ", unknown prefix '" . $array[0] . "'!";
223
        }
224
	} else if (sizeOf($array) == 1) {
225
226
        if (file_exists(ROOT_PATH . "system/classes/" . strtolower($classname) . ".php")) {
227
            include ROOT_PATH . "system/classes/" . strtolower($classname) . ".php";
228
        } else if (file_exists(ROOT_PATH . "system/libs/smarty/sysplugins/" . strtolower($classname) . "php")) {
229
            require ROOT_PATH . "system/libs/smarty/sysplugins/" . strtolower($classname) . ".php";
230
        } else if (strpos($classname, "Plugin") !== FALSE) {
231
			//dwoo tries several times to load a class - with and without namespace, so we hide this error message
232
		} else {
233
            echo "Could not load class '" . $classname . "'' (array size 1)!";
234
        }
235
236
    }
237
238
}
239
240
241
?>
0 ignored issues
show
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
242