[FEATURE] Add a download method to t3lib_http_Request
[Packages/TYPO3.CMS.git] / t3lib / http / observer / class.t3lib_http_observer_download.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2011 Philipp Gampe (dev.typo3@philippgampe.info)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28 /**
29 * Observer to automatically save a http request chunk by chunk to a file.
30 * If the file already exists, it will be overwritten.
31 * This follows an example in HTTP_Request2 manual.
32 *
33 * @see http://pear.php.net/manual/en/package.http.http-request2.observers.php
34 * @author Philipp Gampe
35 */
36 class t3lib_http_observer_Download implements SplObserver {
37
38 /**
39 * @var resource A file pointer resource
40 */
41 protected $filePointer = FALSE;
42
43 /**
44 * @var string The full filename including the leading directory
45 */
46 protected $targetFilePath = '';
47
48 /**
49 * @var string The name of the target directory
50 */
51 protected $targetDirectory = '';
52
53 /**
54 * @var string The name of the target file
55 */
56 protected $targetFilename = '';
57
58 /**
59 * Constructor
60 *
61 * @throws InvalidArgumentException if directory is not found or is not within the PATH_site
62 * or within the lockRootPath
63 * @param string $directory The absolute path to the directory in which the file is saved.
64 * A trailing '/' is removed automatically.
65 * @param string $filename The filename - if not set, it is determined automatically.
66 */
67 public function __construct($directory, $filename = '') {
68 $this->setDirectory($directory);
69 $this->setFilename($filename);
70 }
71
72 /**
73 * Saves current chunk to disk each time a body part is received.
74 * If the filename is empty, tries to determine it from received headers
75 *
76 * @throws t3lib_exception if file can not be opened
77 * @throws UnexpectedValueException if the file name is empty and can not be determined from headers
78 * @param SplSubject|HTTP_Request2 $request
79 * @return void
80 */
81 public function update(SplSubject $request) {
82 $event = $request->getLastEvent();
83
84 switch ($event['name']) {
85 case 'receivedHeaders':
86 if ($this->targetFilename === '') {
87 $this->determineFilename($request, $event['data']);
88 }
89 $this->openFile();
90 break;
91 case 'receivedBodyPart':
92 // Fall through
93 case 'receivedEncodedBodyPart':
94 fwrite($this->filePointer, $event['data']);
95 break;
96 case 'receivedBody':
97 $this->closeFile();
98 break;
99 default:
100 // do nothing
101 }
102 }
103
104 /**
105 * Sets the directory and checks whether the directory is available.
106 *
107 * @throws InvalidArgumentException if directory is not found or is not within the PATH_site
108 * or within the lockRootPath
109 * @param string $directory The absolute path to the directory in which the file is saved.
110 * @return void
111 */
112 public function setDirectory($directory) {
113 if (!is_dir($directory)) {
114 throw new InvalidArgumentException($directory . ' is not a directory', 1312223779);
115 }
116 if (!t3lib_div::isAllowedAbsPath($directory)) {
117 throw new InvalidArgumentException($directory . ' is not within the PATH_site'
118 . ' OR within the lockRootPath', 1328734617);
119 }
120 $this->targetDirectory = $directory = rtrim($directory, DIRECTORY_SEPARATOR);
121 }
122
123 /**
124 * Sets the filename.
125 *
126 * If the file already exists, it will be overridden
127 *
128 * @param string $filename The filename
129 * @return void
130 */
131 public function setFilename($filename = '') {
132 $this->targetFilename = basename($filename);
133 }
134
135 /**
136 * Determines the filename from either the 'content-disposition' header
137 * or from the basename of the current request.
138 *
139 * @param HTTP_Request2 $request
140 * @param HTTP_Request2_Response $response
141 * @return void
142 */
143 protected function determineFilename(HTTP_Request2 $request, HTTP_Request2_Response $response) {
144 $matches = array();
145
146 $disposition = $response->getHeader('content-disposition');
147 if ($disposition !== NULL
148 && 0 === strpos($disposition, 'attachment')
149 && 1 === preg_match('/filename="([^"]+)"/', $disposition, $matches)) {
150 $filename = basename($matches[1]);
151 } else {
152 $filename = basename($request->getUrl()->getPath());
153 }
154 $this->setFilename($filename);
155 }
156
157 /**
158 * Determines the absolute path to the file by combining the directory and filename.
159 * Afterwards tries to open the file for writing.
160 *
161 * $this->filename must be set before calling this function.
162 *
163 * @throws UnexpectedValueException if $this->filename is not set
164 * @throws t3lib_exception if file can not be opened
165 * @return void
166 */
167 protected function openFile() {
168 if ($this->targetFilename === '') {
169 throw new UnexpectedValueException('The file name must not be empty', 1321113658);
170 }
171 $this->targetFilePath = $this->targetDirectory . DIRECTORY_SEPARATOR . $this->targetFilename;
172 $this->filePointer = @fopen($this->targetFilePath, 'wb');
173
174 if ($this->filePointer === FALSE) {
175 throw new t3lib_exception('Cannot open target file ' . $this->targetFilePath, 1320833203);
176 }
177 }
178
179 /**
180 * Closes the file handler and fixes permissions.
181 *
182 * @return void
183 */
184 protected function closeFile() {
185 fclose($this->filePointer);
186 $this->filePointer = FALSE;
187 t3lib_div::fixPermissions($this->targetFilePath);
188 }
189 }
190
191 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/http/observer/class.t3lib_http_observer_download.php'])) {
192 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/http/observer/class.t3lib_http_observer_download.php']);
193 }
194
195 ?>