Diff: STRATO-apps/wordpress_03/app/wp-content/plugins/aimogen-pro/update-checker/Puc/v5p6/PucFactory.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 +
3 + namespace YahnisElsts\PluginUpdateChecker\v5p6;
4 +
5 + use YahnisElsts\PluginUpdateChecker\v5p6\Plugin;
6 + use YahnisElsts\PluginUpdateChecker\v5p6\Theme;
7 + use YahnisElsts\PluginUpdateChecker\v5p6\Vcs;
8 +
9 + if ( !class_exists(PucFactory::class, false) ):
10 +
11 + /**
12 + * A factory that builds update checker instances.
13 + *
14 + * When multiple versions of the same class have been loaded (e.g. PluginUpdateChecker 4.0
15 + * and 4.1), this factory will always use the latest available minor version. Register class
16 + * versions by calling {@link PucFactory::addVersion()}.
17 + *
18 + * At the moment it can only build instances of the UpdateChecker class. Other classes are
19 + * intended mainly for internal use and refer directly to specific implementations.
20 + */
21 + class PucFactory {
22 + protected static $classVersions = array();
23 + protected static $sorted = false;
24 +
25 + protected static $myMajorVersion = '';
26 + protected static $latestCompatibleVersion = '';
27 +
28 + /**
29 + * A wrapper method for buildUpdateChecker() that reads the metadata URL from the plugin or theme header.
30 + *
31 + * @param string $fullPath Full path to the main plugin file or the theme's style.css.
32 + * @param array $args Optional arguments. Keys should match the argument names of the buildUpdateChecker() method.
33 + * @return Plugin\UpdateChecker|Theme\UpdateChecker|Vcs\BaseChecker
34 + */
35 + public static function buildFromHeader($fullPath, $args = array()) {
36 + $fullPath = self::normalizePath($fullPath);
37 +
38 + //Set up defaults.
39 + $defaults = array(
40 + 'metadataUrl' => '',
41 + 'slug' => '',
42 + 'checkPeriod' => 12,
43 + 'optionName' => '',
44 + 'muPluginFile' => '',
45 + );
46 + $args = array_merge($defaults, array_intersect_key($args, $defaults));
47 + extract($args, EXTR_SKIP);
48 +
49 + //Check for the service URI
50 + if ( empty($metadataUrl) ) {
51 + $metadataUrl = self::getServiceURI($fullPath);
52 + }
53 +
54 + return self::buildUpdateChecker($metadataUrl, $fullPath, $slug, $checkPeriod, $optionName, $muPluginFile);
55 + }
56 +
57 + /**
58 + * Create a new instance of the update checker.
59 + *
60 + * This method automatically detects if you're using it for a plugin or a theme and chooses
61 + * the appropriate implementation for your update source (JSON file, GitHub, BitBucket, etc).
62 + *
63 + * @see UpdateChecker::__construct
64 + *
65 + * @param string $metadataUrl The URL of the metadata file, a GitHub repository, or another supported update source.
66 + * @param string $fullPath Full path to the main plugin file or to the theme directory.
67 + * @param string $slug Custom slug. Defaults to the name of the main plugin file or the theme directory.
68 + * @param int $checkPeriod How often to check for updates (in hours).
69 + * @param string $optionName Where to store bookkeeping info about update checks.
70 + * @param string $muPluginFile The plugin filename relative to the mu-plugins directory.
71 + * @return Plugin\UpdateChecker|Theme\UpdateChecker|Vcs\BaseChecker
72 + */
73 + public static function buildUpdateChecker($metadataUrl, $fullPath, $slug = '', $checkPeriod = 12, $optionName = '', $muPluginFile = '') {
74 + $fullPath = self::normalizePath($fullPath);
75 + $id = null;
76 +
77 + //Plugin or theme?
78 + $themeDirectory = self::getThemeDirectoryName($fullPath);
79 + if ( self::isPluginFile($fullPath) ) {
80 + $type = 'Plugin';
81 + $id = $fullPath;
82 + } else if ( $themeDirectory !== null ) {
83 + $type = 'Theme';
84 + $id = $themeDirectory;
85 + } else {
86 + throw new \RuntimeException(sprintf(
87 + 'The update checker cannot determine if "%s" is a plugin or a theme. ' .
88 + 'This is a bug. Please contact the PUC developer.',
89 + htmlentities($fullPath)
90 + ));
91 + }
92 +
93 + //Which hosting service does the URL point to?
94 + $service = self::getVcsService($metadataUrl);
95 +
96 + $apiClass = null;
97 + if ( empty($service) ) {
98 + //The default is to get update information from a remote JSON file.
99 + $checkerClass = $type . '\\UpdateChecker';
100 + } else {
101 + //You can also use a VCS repository like GitHub.
102 + $checkerClass = 'Vcs\\' . $type . 'UpdateChecker';
103 + $apiClass = $service . 'Api';
104 + }
105 +
106 + $checkerClass = self::getCompatibleClassVersion($checkerClass);
107 + if ( $checkerClass === null ) {
108 + //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
109 + trigger_error(
110 + esc_html(sprintf(
111 + 'PUC %s does not support updates for %ss %s',
112 + self::$latestCompatibleVersion,
113 + strtolower($type),
114 + $service ? ('hosted on ' . $service) : 'using JSON metadata'
115 + )),
116 + E_USER_ERROR
117 + );
118 + }
119 +
120 + if ( !isset($apiClass) ) {
121 + //Plain old update checker.
122 + return new $checkerClass($metadataUrl, $id, $slug, $checkPeriod, $optionName, $muPluginFile);
123 + } else {
124 + //VCS checker + an API client.
125 + $apiClass = self::getCompatibleClassVersion($apiClass);
126 + if ( $apiClass === null ) {
127 + //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
128 + trigger_error(esc_html(sprintf(
129 + 'PUC %s does not support %s',
130 + self::$latestCompatibleVersion,
131 + $service
132 + )), E_USER_ERROR);
133 + }
134 +
135 + return new $checkerClass(
136 + new $apiClass($metadataUrl),
137 + $id,
138 + $slug,
139 + $checkPeriod,
140 + $optionName,
141 + $muPluginFile
142 + );
143 + }
144 + }
145 +
146 + /**
147 + *
148 + * Normalize a filesystem path. Introduced in WP 3.9.
149 + * Copying here allows use of the class on earlier versions.
150 + * This version adapted from WP 4.8.2 (unchanged since 4.5.6)
151 + *
152 + * @param string $path Path to normalize.
153 + * @return string Normalized path.
154 + */
155 + public static function normalizePath($path) {
156 + if ( function_exists('wp_normalize_path') ) {
157 + return wp_normalize_path($path);
158 + }
159 + $path = str_replace('\\', '/', $path);
160 + $path = preg_replace('|(?<=.)/+|', '/', $path);
161 + if ( substr($path, 1, 1) === ':' ) {
162 + $path = ucfirst($path);
163 + }
164 + return $path;
165 + }
166 +
167 + /**
168 + * Check if the path points to a plugin file.
169 + *
170 + * @param string $absolutePath Normalized path.
171 + * @return bool
172 + */
173 + protected static function isPluginFile($absolutePath) {
174 + //Is the file inside the "plugins" or "mu-plugins" directory?
175 + $pluginDir = self::normalizePath(WP_PLUGIN_DIR);
176 + $muPluginDir = self::normalizePath(WPMU_PLUGIN_DIR);
177 + if ( (strpos($absolutePath, $pluginDir) === 0) || (strpos($absolutePath, $muPluginDir) === 0) ) {
178 + return true;
179 + }
180 +
181 + //Is it a file at all? Caution: is_file() can fail if the parent dir. doesn't have the +x permission set.
182 + if ( !is_file($absolutePath) ) {
183 + return false;
184 + }
185 +
186 + //Does it have a valid plugin header?
187 + //This is a last-ditch check for plugins symlinked from outside the WP root.
188 + if ( function_exists('get_file_data') ) {
189 + $headers = get_file_data($absolutePath, array('Name' => 'Plugin Name'), 'plugin');
190 + return !empty($headers['Name']);
191 + }
192 +
193 + return false;
194 + }
195 +
196 + /**
197 + * Get the name of the theme's directory from a full path to a file inside that directory.
198 + * E.g. "/abc/public_html/wp-content/themes/foo/whatever.php" => "foo".
199 + *
200 + * Note that subdirectories are currently not supported. For example,
201 + * "/xyz/wp-content/themes/my-theme/includes/whatever.php" => NULL.
202 + *
203 + * @param string $absolutePath Normalized path.
204 + * @return string|null Directory name, or NULL if the path doesn't point to a theme.
205 + */
206 + protected static function getThemeDirectoryName($absolutePath) {
207 + if ( is_file($absolutePath) ) {
208 + $absolutePath = dirname($absolutePath);
209 + }
210 +
211 + if ( file_exists($absolutePath . '/style.css') ) {
212 + return basename($absolutePath);
213 + }
214 + return null;
215 + }
216 +
217 + /**
218 + * Get the service URI from the file header.
219 + *
220 + * @param string $fullPath
221 + * @return string
222 + */
223 + private static function getServiceURI($fullPath) {
224 + //Look for the URI
225 + if ( is_readable($fullPath) ) {
226 + $seek = array(
227 + 'github' => 'GitHub URI',
228 + 'gitlab' => 'GitLab URI',
229 + 'bucket' => 'BitBucket URI',
230 + );
231 + $seek = apply_filters('puc_get_source_uri', $seek);
232 + $data = get_file_data($fullPath, $seek);
233 + foreach ($data as $key => $uri) {
234 + if ( $uri ) {
235 + return $uri;
236 + }
237 + }
238 + }
239 +
240 + //URI was not found so throw an error.
241 + throw new \RuntimeException(
242 + sprintf('Unable to locate URI in header of "%s"', htmlentities($fullPath))
243 + );
244 + }
245 +
246 + /**
247 + * Get the name of the hosting service that the URL points to.
248 + *
249 + * @param string $metadataUrl
250 + * @return string|null
251 + */
252 + private static function getVcsService($metadataUrl) {
253 + $service = null;
254 +
255 + //Which hosting service does the URL point to?
256 + $host = (string)(wp_parse_url($metadataUrl, PHP_URL_HOST));
257 + $path = (string)(wp_parse_url($metadataUrl, PHP_URL_PATH));
258 +
259 + //Check if the path looks like "/user-name/repository".
260 + //For GitLab.com it can also be "/user/group1/group2/.../repository".
261 + $repoRegex = '@^/?([^/]+?)/([^/#?&]+?)/?$@';
262 + if ( $host === 'gitlab.com' ) {
263 + $repoRegex = '@^/?(?:[^/#?&]++/){1,20}(?:[^/#?&]++)/?$@';
264 + }
265 + if ( preg_match($repoRegex, $path) ) {
266 + $knownServices = array(
267 + 'github.com' => 'GitHub',
268 + 'bitbucket.org' => 'BitBucket',
269 + 'gitlab.com' => 'GitLab',
270 + );
271 + if ( isset($knownServices[$host]) ) {
272 + $service = $knownServices[$host];
273 + }
274 + }
275 +
276 + return apply_filters('puc_get_vcs_service', $service, $host, $path, $metadataUrl);
277 + }
278 +
279 + /**
280 + * Get the latest version of the specified class that has the same major version number
281 + * as this factory class.
282 + *
283 + * @param string $class Partial class name.
284 + * @return string|null Full class name.
285 + */
286 + protected static function getCompatibleClassVersion($class) {
287 + if ( isset(self::$classVersions[$class][self::$latestCompatibleVersion]) ) {
288 + return self::$classVersions[$class][self::$latestCompatibleVersion];
289 + }
290 + return null;
291 + }
292 +
293 + /**
294 + * Get the specific class name for the latest available version of a class.
295 + *
296 + * @param string $class
297 + * @return null|string
298 + */
299 + public static function getLatestClassVersion($class) {
300 + if ( !self::$sorted ) {
301 + self::sortVersions();
302 + }
303 +
304 + if ( isset(self::$classVersions[$class]) ) {
305 + return reset(self::$classVersions[$class]);
306 + } else {
307 + return null;
308 + }
309 + }
310 +
311 + /**
312 + * Sort available class versions in descending order (i.e. newest first).
313 + */
314 + protected static function sortVersions() {
315 + foreach ( self::$classVersions as $class => $versions ) {
316 + uksort($versions, array(__CLASS__, 'compareVersions'));
317 + self::$classVersions[$class] = $versions;
318 + }
319 + self::$sorted = true;
320 + }
321 +
322 + protected static function compareVersions($a, $b) {
323 + return -version_compare($a, $b);
324 + }
325 +
326 + /**
327 + * Register a version of a class.
328 + *
329 + * @access private This method is only for internal use by the library.
330 + *
331 + * @param string $generalClass Class name without version numbers, e.g. 'PluginUpdateChecker'.
332 + * @param string $versionedClass Actual class name, e.g. 'PluginUpdateChecker_1_2'.
333 + * @param string $version Version number, e.g. '1.2'.
334 + */
335 + public static function addVersion($generalClass, $versionedClass, $version) {
336 + if ( empty(self::$myMajorVersion) ) {
337 + $lastNamespaceSegment = substr(__NAMESPACE__, strrpos(__NAMESPACE__, '\\') + 1);
338 + self::$myMajorVersion = substr(ltrim($lastNamespaceSegment, 'v'), 0, 1);
339 + }
340 +
341 + //Store the greatest version number that matches our major version.
342 + $components = explode('.', $version);
343 + if ( $components[0] === self::$myMajorVersion ) {
344 +
345 + if (
346 + empty(self::$latestCompatibleVersion)
347 + || version_compare($version, self::$latestCompatibleVersion, '>')
348 + ) {
349 + self::$latestCompatibleVersion = $version;
350 + }
351 +
352 + }
353 +
354 + if ( !isset(self::$classVersions[$generalClass]) ) {
355 + self::$classVersions[$generalClass] = array();
356 + }
357 + self::$classVersions[$generalClass][$version] = $versionedClass;
358 + self::$sorted = false;
359 + }
360 + }
361 +
362 + endif;
363 +