IOHelper::copyFile()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 10
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Input and output helper
5
 *
6
 * PHP Version 5.2.6
7
 *
8
 * Copyright (c) 2007-2009, Mayflower GmbH
9
 * All rights reserved.
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 *
15
 *   * Redistributions of source code must retain the above copyright
16
 *     notice, this list of conditions and the following disclaimer.
17
 *
18
 *   * Redistributions in binary form must reproduce the above copyright
19
 *     notice, this list of conditions and the following disclaimer in
20
 *     the documentation and/or other materials provided with the
21
 *     distribution.
22
 *
23
 *   * Neither the name of Mayflower GmbH nor the names of his
24
 *     contributors may be used to endorse or promote products derived
25
 *     from this software without specific prior written permission.
26
 *
27
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
 * POSSIBILITY OF SUCH DAMAGE.
39
 *
40
 * @category PHP_CodeBrowser
41
 *
42
 * @author Elger Thiele <[email protected]>
43
 *
44
 * @copyright 2007-2009 Mayflower GmbH
45
 *
46
 * @license http://www.opensource.org/licenses/bsd-license.php  BSD License
47
 *
48
 * @version SVN: $Id$
49
 *
50
 * @link http://www.phpunit.de/
51
 *
52
 * @since File available since  0.1.0
53
 */
54
55
namespace PHPCodeBrowser\Helper;
56
57
use DirectoryIterator;
58
59
/**
60
 * IOHelper
61
 *
62
 * Input output helper class provides several methods for writing and
63
 * reading files or directories.
64
 *
65
 * @category PHP_CodeBrowser
66
 *
67
 * @author Elger Thiele <[email protected]>
68
 * @author Christopher Weckerle <[email protected]>
69
 *
70
 * @copyright 2007-2009 Mayflower GmbH
71
 *
72
 * @license http://www.opensource.org/licenses/bsd-license.php  BSD License
73
 *
74
 * @version Release: @package_version@
75
 *
76
 * @link http://www.phpunit.de/
77
 *
78
 * @since Class available since  0.1.0
79
 */
80
class IOHelper
81
{
82
    /**
83
     * Creates a file with given name and content.
84
     * If directories to file do not exists they will be created.
85
     *
86
     * @param string $fileName    The filename
87
     * @param string $fileContent The content of the file
88
     *
89
     * @return void
90
     */
91
    public function createFile(string $fileName, string $fileContent): void
92
    {
93
        $realName = \basename($fileName);
94
        $path     = \substr($fileName, 0, - 1 * (\strlen($realName)));
95
96
        if (!empty($path)) {
97
            $this->createDirectory($path);
98
        }
99
100
        \file_put_contents(\realpath($path).'/'.$realName, $fileContent);
101
    }
102
103
    /**
104
     * Delete a file. The filename could inherit a absolute or relative
105
     * path-to-file,
106
     * e.g. foo/bar/myFile.php
107
     *
108
     * @param string $fileName The (path-to) filename
109
     *
110
     * @return void
111
     */
112
    public function deleteFile(string $fileName): void
113
    {
114
        if (!\file_exists($fileName)) {
115
            return;
116
        }
117
118
        \unlink($fileName);
119
    }
120
121
    /**
122
     * Copy a file from a source to target dir. The source could inherit an
123
     * absolute or relative path-to-file.
124
     *
125
     * @param string $fileSource   The source file
126
     * @param string $sourceFolder The target folder
127
     *
128
     * @return void
129
     *
130
     * @throws \Exception
131
     */
132
    public function copyFile(string $fileSource, string $sourceFolder): void
133
    {
134
        if (!\file_exists($fileSource)) {
135
            throw new \Exception(\sprintf('File %s does not exist!', $fileSource));
136
        }
137
138
        $fileName = \basename($fileSource);
139
        $this->createFile(
140
            $sourceFolder.'/'.$fileName,
141
            $this->loadFile($fileSource)
142
        );
143
    }
144
145
    /**
146
     * Return the content of a given file.
147
     *
148
     * @param string $fileName The file the content should be read in
149
     *
150
     * @return string
151
     *
152
     * @throws \Exception
153
     */
154
    public function loadFile(string $fileName): string
155
    {
156
        if (!\file_exists($fileName)) {
157
            throw new \Exception(\sprintf('File %s does not exist!', $fileName));
158
        }
159
160
        return \trim(\file_get_contents($fileName));
161
    }
162
163
    /**
164
     * Create a directory and its inherit path to directory if not present,
165
     * e.g. path/that/does/not/exist/myFolder/
166
     *
167
     * @param string $target The target folder to create
168
     *
169
     * @return void
170
     */
171
    public function createDirectory(string $target): void
172
    {
173
        $target = \rtrim($target, DIRECTORY_SEPARATOR);
174
175
        if (\is_dir($target)) {
176
            return;
177
        }
178
179
        if (!\mkdir($target, 0777, true) && !\is_dir($target)) {
180
            throw new \RuntimeException(\sprintf('Directory "%s" was not created', $target));
181
        }
182
    }
183
184
    /**
185
     * Delete a directory within all its items.
186
     * Note that the given directory $source will be deleted as well.
187
     *
188
     * @param string $source The directory to delete.
189
     *
190
     * @throws \Exception
191
     *
192
     * @return void
193
     */
194
    public function deleteDirectory(string $source): void
195
    {
196
        $iterator = new DirectoryIterator($source);
197
198
        while ($iterator->valid()) {
199
            $src = \realpath($source.'/'.$iterator->current());
200
201
            // delete file
202
            if ($iterator->isFile()) {
203
                $this->deleteFile($src);
204
            }
205
206
            // delete folder recursive
207
            if (!$iterator->isDot() && $iterator->isDir()) {
208
                $this->deleteDirectory($src);
209
            }
210
211
            $iterator->next();
212
        }
213
214
        unset($iterator);
215
216
        // delete the source root folder as well
217
        if (!\rmdir($source)) {
218
            throw new \Exception(\sprintf('Could not delete directory %s', $source));
219
        }
220
    }
221
222
    /**
223
     * Copy a directory within all its items.
224
     *
225
     * @param string $source The source directory
226
     * @param string $target The target to create
227
     *
228
     * @return void
229
     */
230
    public function copyDirectory(string $source, string $target): void
231
    {
232
        // first check for target itself
233
        $this->createDirectory($target);
234
        $iterator = new DirectoryIterator($source);
235
236
        while ($iterator->valid()) {
237
            $item = $iterator->current();
238
239
            // create new file
240
            if ($iterator->isFile()) {
241
                $this->copyFile($source.'/'.$item, $target);
242
            }
243
244
            // create folder recursive
245
            if (!$iterator->isDot()
246
                && $iterator->isDir()
247
            ) {
248
                $this->copyDirectory(
249
                    $source.'/'.$item,
250
                    $target.'/'.$item
251
                );
252
            }
253
254
            $iterator->next();
255
        }
256
    }
257
258
    /**
259
     * Get the prefix all paths in an array of paths have in common.
260
     *
261
     * @param array $fileNames
262
     *
263
     * @return string
264
     */
265
    public static function getCommonPathPrefix(array $fileNames): string
266
    {
267
        if (empty($fileNames)) {
268
            return '/';
269
        }
270
271
        $prefix = \dirname(\array_shift($fileNames));
272
273
        foreach ($fileNames as $filename) {
274
            $prefix = self::getCurrentCommonPathPrefix($prefix, $filename);
275
        }
276
277
        if (\substr($prefix, -1, 1) !== DIRECTORY_SEPARATOR) {
278
            $prefix .= DIRECTORY_SEPARATOR;
279
        }
280
281
        return $prefix;
282
    }
283
284
    /**
285
     * Get the part of currentPrefix that currentPrefix and path have in common.
286
     *
287
     * @param string $currentPrefix
288
     * @param string $path
289
     *
290
     * @return string
291
     */
292
    protected static function getCurrentCommonPathPrefix(string $currentPrefix, string $path): string
293
    {
294
        if (\str_starts_with($path, $currentPrefix.DIRECTORY_SEPARATOR)
295
            || DIRECTORY_SEPARATOR === $currentPrefix
296
            || '' === $currentPrefix
297
            || '.' === $currentPrefix
298
            || \preg_match('/^[A-Z]\:\\\\$/', $currentPrefix) === 1
299
        ) {
300
            return $currentPrefix;
301
        }
302
303
        return self::getCurrentCommonPathPrefix(\dirname($currentPrefix), $path);
304
    }
305
}
306