|
1
|
|
|
<?php defined('SYSPATH') or die('No direct access allowed.'); |
|
2
|
|
|
/** |
|
3
|
|
|
* File helper class. |
|
4
|
|
|
* |
|
5
|
|
|
* $Id: file.php 3769 2008-12-15 00:48:56Z zombor $ |
|
6
|
|
|
* |
|
7
|
|
|
* @package Core |
|
8
|
|
|
* @author Kohana Team |
|
9
|
|
|
* @copyright (c) 2007-2008 Kohana Team |
|
10
|
|
|
* @license http://kohanaphp.com/license.html |
|
11
|
|
|
*/ |
|
12
|
|
|
class file_Core |
|
13
|
|
|
{ |
|
14
|
|
|
|
|
15
|
|
|
/** |
|
16
|
|
|
* Attempt to get the mime type from a file. This method is horribly |
|
17
|
|
|
* unreliable, due to PHP being horribly unreliable when it comes to |
|
18
|
|
|
* determining the mime-type of a file. |
|
19
|
|
|
* |
|
20
|
|
|
* @param string filename |
|
21
|
|
|
* @return string mime-type, if found |
|
22
|
|
|
* @return boolean FALSE, if not found |
|
23
|
|
|
*/ |
|
24
|
|
|
public static function mime($filename) |
|
25
|
|
|
{ |
|
26
|
|
|
// Make sure the file is readable |
|
27
|
|
|
if (! (is_file($filename) and is_readable($filename))) { |
|
28
|
|
|
return false; |
|
|
|
|
|
|
29
|
|
|
} |
|
30
|
|
|
|
|
31
|
|
|
// Get the extension from the filename |
|
32
|
|
|
$extension = strtolower(substr(strrchr($filename, '.'), 1)); |
|
33
|
|
|
|
|
34
|
|
|
if (preg_match('/^(?:jpe?g|png|[gt]if|bmp|swf)$/', $extension)) { |
|
35
|
|
|
// Disable error reporting |
|
36
|
|
|
$ER = error_reporting(0); |
|
|
|
|
|
|
37
|
|
|
|
|
38
|
|
|
// Use getimagesize() to find the mime type on images |
|
39
|
|
|
$mime = getimagesize($filename); |
|
40
|
|
|
|
|
41
|
|
|
// Turn error reporting back on |
|
42
|
|
|
error_reporting($ER); |
|
43
|
|
|
|
|
44
|
|
|
// Return the mime type |
|
45
|
|
|
if (isset($mime['mime'])) { |
|
46
|
|
|
return $mime['mime']; |
|
47
|
|
|
} |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
|
|
if (function_exists('finfo_open')) { |
|
51
|
|
|
// Use the fileinfo extension |
|
52
|
|
|
$finfo = finfo_open(FILEINFO_MIME); |
|
53
|
|
|
$mime = finfo_file($finfo, $filename); |
|
54
|
|
|
finfo_close($finfo); |
|
55
|
|
|
|
|
56
|
|
|
// Return the mime type |
|
57
|
|
|
return $mime; |
|
58
|
|
|
} |
|
59
|
|
|
|
|
60
|
|
|
if (ini_get('mime_magic.magicfile') and function_exists('mime_content_type')) { |
|
61
|
|
|
// Return the mime type using mime_content_type |
|
62
|
|
|
return mime_content_type($filename); |
|
63
|
|
|
} |
|
64
|
|
|
|
|
65
|
|
|
if (! KOHANA_IS_WIN) { |
|
66
|
|
|
// Attempt to locate use the file command, checking the return value |
|
67
|
|
|
if ($command = trim(exec('which file', $output, $return)) and $return === 0) { |
|
68
|
|
|
return trim(exec($command.' -bi '.escapeshellarg($filename))); |
|
69
|
|
|
} |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
if (! empty($extension) and is_array($mime = Kohana::config('mimes.'.$extension))) { |
|
73
|
|
|
// Return the mime-type guess, based on the extension |
|
74
|
|
|
return $mime[0]; |
|
75
|
|
|
} |
|
76
|
|
|
|
|
77
|
|
|
// Unable to find the mime-type |
|
78
|
|
|
return false; |
|
|
|
|
|
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* Split a file into pieces matching a specific size. |
|
83
|
|
|
* |
|
84
|
|
|
* @param string file to be split |
|
85
|
|
|
* @param string directory to output to, defaults to the same directory as the file |
|
86
|
|
|
* @param integer size, in MB, for each chunk to be |
|
87
|
|
|
* @return integer The number of pieces that were created. |
|
88
|
|
|
*/ |
|
89
|
|
|
public static function split($filename, $output_dir = false, $piece_size = 10) |
|
90
|
|
|
{ |
|
91
|
|
|
// Find output dir |
|
92
|
|
|
$output_dir = ($output_dir == false) ? pathinfo(str_replace('\\', '/', realpath($filename)), PATHINFO_DIRNAME) : str_replace('\\', '/', realpath($output_dir)); |
|
|
|
|
|
|
93
|
|
|
$output_dir = rtrim($output_dir, '/').'/'; |
|
|
|
|
|
|
94
|
|
|
|
|
95
|
|
|
// Open files for writing |
|
96
|
|
|
$input_file = fopen($filename, 'rb'); |
|
97
|
|
|
|
|
98
|
|
|
// Change the piece size to bytes |
|
99
|
|
|
$piece_size = 1024 * 1024 * (int) $piece_size; // Size in bytes |
|
100
|
|
|
|
|
101
|
|
|
// Set up reading variables |
|
102
|
|
|
$read = 0; // Number of bytes read |
|
103
|
|
|
$piece = 1; // Current piece |
|
104
|
|
|
$chunk = 1024 * 8; // Chunk size to read |
|
105
|
|
|
|
|
106
|
|
|
// Split the file |
|
107
|
|
|
while (! feof($input_file)) { |
|
108
|
|
|
// Open a new piece |
|
109
|
|
|
$piece_name = $filename.'.'.str_pad($piece, 3, '0', STR_PAD_LEFT); |
|
110
|
|
|
$piece_open = @fopen($piece_name, 'wb+') or die('Could not write piece '.$piece_name); |
|
|
|
|
|
|
111
|
|
|
|
|
112
|
|
|
// Fill the current piece |
|
113
|
|
|
while ($read < $piece_size and $data = fread($input_file, $chunk)) { |
|
114
|
|
|
fwrite($piece_open, $data) or die('Could not write to open piece '.$piece_name); |
|
|
|
|
|
|
115
|
|
|
$read += $chunk; |
|
116
|
|
|
} |
|
117
|
|
|
|
|
118
|
|
|
// Close the current piece |
|
119
|
|
|
fclose($piece_open); |
|
120
|
|
|
|
|
121
|
|
|
// Prepare to open a new piece |
|
122
|
|
|
$read = 0; |
|
123
|
|
|
$piece++; |
|
124
|
|
|
|
|
125
|
|
|
// Make sure that piece is valid |
|
126
|
|
|
($piece < 999) or die('Maximum of 999 pieces exceeded, try a larger piece size'); |
|
|
|
|
|
|
127
|
|
|
} |
|
128
|
|
|
|
|
129
|
|
|
// Close input file |
|
130
|
|
|
fclose($input_file); |
|
131
|
|
|
|
|
132
|
|
|
// Returns the number of pieces that were created |
|
133
|
|
|
return ($piece - 1); |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
/** |
|
137
|
|
|
* Join a split file into a whole file. |
|
138
|
|
|
* |
|
139
|
|
|
* @param string split filename, without .000 extension |
|
140
|
|
|
* @param string output filename, if different then an the filename |
|
141
|
|
|
* @return integer The number of pieces that were joined. |
|
142
|
|
|
*/ |
|
143
|
|
|
public static function join($filename, $output = false) |
|
144
|
|
|
{ |
|
145
|
|
|
if ($output == false) { |
|
|
|
|
|
|
146
|
|
|
$output = $filename; |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
// Set up reading variables |
|
150
|
|
|
$piece = 1; // Current piece |
|
151
|
|
|
$chunk = 1024 * 8; // Chunk size to read |
|
152
|
|
|
|
|
153
|
|
|
// Open output file |
|
154
|
|
|
$output_file = @fopen($output, 'wb+') or die('Could not open output file '.$output); |
|
|
|
|
|
|
155
|
|
|
|
|
156
|
|
|
// Read each piece |
|
157
|
|
|
while ($piece_open = @fopen(($piece_name = $filename.'.'.str_pad($piece, 3, '0', STR_PAD_LEFT)), 'rb')) { |
|
158
|
|
|
// Write the piece into the output file |
|
159
|
|
|
while (! feof($piece_open)) { |
|
160
|
|
|
fwrite($output_file, fread($piece_open, $chunk)); |
|
161
|
|
|
} |
|
162
|
|
|
|
|
163
|
|
|
// Close the current piece |
|
164
|
|
|
fclose($piece_open); |
|
165
|
|
|
|
|
166
|
|
|
// Prepare for a new piece |
|
167
|
|
|
$piece++; |
|
168
|
|
|
|
|
169
|
|
|
// Make sure piece is valid |
|
170
|
|
|
($piece < 999) or die('Maximum of 999 pieces exceeded'); |
|
|
|
|
|
|
171
|
|
|
} |
|
172
|
|
|
|
|
173
|
|
|
// Close the output file |
|
174
|
|
|
fclose($output_file); |
|
175
|
|
|
|
|
176
|
|
|
// Return the number of pieces joined |
|
177
|
|
|
return ($piece - 1); |
|
178
|
|
|
} |
|
179
|
|
|
} // End file |
|
180
|
|
|
|
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_functionexpects aPostobject, and outputs the author of the post. The base classPostreturns a simple string and outputting a simple string will work just fine. However, the child classBlogPostwhich is a sub-type ofPostinstead decided to return anobject, and is therefore violating the SOLID principles. If aBlogPostwere passed tomy_function, PHP would not complain, but ultimately fail when executing thestrtouppercall in its body.