Version 1
[yaffs-website] / vendor / alchemy / zippy / src / Resource / TargetLocator.php
1 <?php
2
3 /*
4  * This file is part of Zippy.
5  *
6  * (c) Alchemy <info@alchemy.fr>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Alchemy\Zippy\Resource;
13
14 use Alchemy\Zippy\Exception\TargetLocatorException;
15
16 class TargetLocator
17 {
18     /**
19      * Locates the target for a resource in a context
20      *
21      * For example, adding /path/to/file where the context (current working
22      * directory) is /path/to will return `file` as target
23      *
24      * @param string          $context
25      * @param string|resource $resource
26      *
27      * @return string
28      *
29      * @throws TargetLocatorException when the resource is invalid
30      */
31     public function locate($context, $resource)
32     {
33         switch (true) {
34             case is_resource($resource):
35                 return $this->locateResource($resource);
36             case is_string($resource):
37                 return $this->locateString($context, $resource);
38             case $resource instanceof \SplFileInfo:
39                 return $this->locateString($context, $resource->getRealPath());
40             default:
41                 throw new TargetLocatorException($resource, 'Unknown resource format');
42         }
43     }
44
45     /**
46      * Locate the target for a resource.
47      *
48      * @param resource $resource
49      *
50      * @return string
51      *
52      * @throws TargetLocatorException
53      */
54     private function locateResource($resource)
55     {
56         $meta = stream_get_meta_data($resource);
57         $data = parse_url($meta['uri']);
58
59         if (!isset($data['path'])) {
60             throw new TargetLocatorException($resource, 'Unable to retrieve path from resource');
61         }
62
63         return PathUtil::basename($data['path']);
64     }
65
66     /**
67      * Locate the target for a string.
68      *
69      * @param        $context
70      * @param string $resource
71      *
72      * @return string
73      *
74      * @throws TargetLocatorException
75      */
76     private function locateString($context, $resource)
77     {
78         $url = parse_url($resource);
79
80         if (isset($url['scheme']) && $this->isLocalFilesystem($url['scheme'])) {
81             $resource = $url['path'] = $this->cleanupPath($url['path']);
82         }
83
84         // resource is a URI
85         if (isset($url['scheme'])) {
86             if ($this->isLocalFilesystem($url['scheme']) && $this->isFileInContext($url['path'], $context)) {
87                 return $this->getRelativePathFromContext($url['path'], $context);
88             }
89
90             return PathUtil::basename($resource);
91         }
92
93         // resource is a local path
94         if ($this->isFileInContext($resource, $context)) {
95             $resource = $this->cleanupPath($resource);
96
97             return $this->getRelativePathFromContext($resource, $context);
98         } else {
99             return PathUtil::basename($resource);
100         }
101     }
102
103     /**
104      * Removes backward path sequences (..)
105      *
106      * @param string $path
107      *
108      * @return string
109      *
110      * @throws TargetLocatorException In case the path is invalid
111      */
112     private function cleanupPath($path)
113     {
114         if (false === $cleanPath = realpath($path)) {
115             throw new TargetLocatorException($path, sprintf('%s is an invalid location', $path));
116         }
117
118         return $cleanPath;
119     }
120
121     /**
122      * Checks whether the path belong to the context
123      *
124      * @param string $path A resource path
125      * @param string $context
126      *
127      * @return bool
128      */
129     private function isFileInContext($path, $context)
130     {
131         return 0 === strpos($path, $context);
132     }
133
134     /**
135      * Gets the relative path from the context for the given path
136      *
137      * @param string $path A resource path
138      * @param string $context
139      *
140      * @return string
141      */
142     private function getRelativePathFromContext($path, $context)
143     {
144         return ltrim(str_replace($context, '', $path), '/\\');
145     }
146
147     /**
148      * Checks if a scheme refers to a local filesystem
149      *
150      * @param string $scheme
151      *
152      * @return bool
153      */
154     private function isLocalFilesystem($scheme)
155     {
156         return 'plainfile' === $scheme || 'file' === $scheme;
157     }
158 }