]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/upload_file.php
Release 6.2.0beta4
[Github/sugarcrm.git] / include / upload_file.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  * Description:
41  ********************************************************************************/
42 require_once('include/externalAPI/ExternalAPIFactory.php');
43
44 class UploadFile 
45 {
46         var $field_name;
47         var $stored_file_name;
48         var $original_file_name;
49         var $temp_file_location;
50         var $use_soap = false;
51         var $file;
52         var $file_ext;
53         
54         function UploadFile ($field_name) {
55                 // $field_name is the name of your passed file selector field in your form
56                 // i.e., for Emails, it is "email_attachmentX" where X is 0-9
57                 $this->field_name = $field_name;
58         // Bug 28408 -  Add automatic creation of upload cache directory if it doesn't exist
59                 if ( !is_dir($GLOBALS['sugar_config']['upload_dir']) ) 
60             create_cache_directory(str_replace($GLOBALS['sugar_config']['cache_dir'],'',$GLOBALS['sugar_config']['upload_dir']));
61         }
62
63         function set_for_soap($filename, $file) {
64                 $this->stored_file_name = $filename;
65                 $this->use_soap = true;
66                 $this->file = $file;
67         }
68
69         /**
70          * wrapper for this::get_file_path()
71          * @param string stored_file_name File name in filesystem
72          * @param string bean_id note bean ID
73          * @return string path with file name
74          */
75         function get_url($stored_file_name,$bean_id) {
76                 global $sugar_config;
77                 return UploadFile::get_file_path($stored_file_name,$bean_id);
78         }
79         
80         /**
81          * builds a URL path for an anchor tag 
82          * @param string stored_file_name File name in filesystem
83          * @param string bean_id note bean ID
84          * @return string path with file name
85          */
86         function get_file_path($stored_file_name,$bean_id) {
87                 global $sugar_config;
88                 global $locale;
89         
90         // if the parameters are empty strings, just return back the upload_dir
91                 if ( empty($bean_id) && empty($stored_file_name) )
92             return $sugar_config['upload_dir'];
93             
94                 if (file_exists($sugar_config['upload_dir'] . $bean_id . rawurlencode($stored_file_name))){
95                         if (!rename($sugar_config['upload_dir'] . $bean_id . rawurlencode($stored_file_name),
96                                    $sugar_config['upload_dir'] . $bean_id)){
97                                 $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}");
98                         }
99                 }
100                 else if (file_exists($sugar_config['upload_dir'] . $bean_id . urlencode($stored_file_name))){
101                         if (!rename($sugar_config['upload_dir'] . $bean_id . urlencode($stored_file_name),
102                                    $sugar_config['upload_dir'] . $bean_id)){
103                                 $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}");
104                         }
105                 } 
106                 else if (file_exists($sugar_config['upload_dir'] . $bean_id . $stored_file_name)){
107                         if (!rename($sugar_config['upload_dir'] . $bean_id . $stored_file_name,
108                                    $sugar_config['upload_dir'] . $bean_id)){
109                                 $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}");
110                         }
111                 }
112                 else if (file_exists($sugar_config['upload_dir'] . $bean_id . $locale->translateCharset( $stored_file_name, 'UTF-8', $locale->getExportCharset() ))){
113                         if (!rename($sugar_config['upload_dir'] . $bean_id . $locale->translateCharset( $stored_file_name, 'UTF-8', $locale->getExportCharset() ), 
114                                                 $sugar_config['upload_dir'] . $bean_id)){
115                                 $GLOBALS['log']->fatal("unable to rename file in {$sugar_config['upload_dir']}");
116                         }
117                 }               
118                                 
119                 return $sugar_config['upload_dir'] . $bean_id;
120         }
121
122         /**
123          * duplicates an already uploaded file in the filesystem.
124          * @param string old_id ID of original note
125          * @param string new_id ID of new (copied) note
126          * @param string filename Filename of file (deprecated)
127          */
128         function duplicate_file($old_id, $new_id, $file_name) {
129                 global $sugar_config;
130
131                 // current file system (GUID)
132                 $source = $sugar_config['upload_dir'] . $old_id;
133                 
134                 if(!file_exists($source)) {
135                         // old-style file system (GUID.filename.extension)
136                         $oldStyleSource = $source.$file_name;
137                         if(file_exists($oldStyleSource)) {
138                                 // change to new style
139                                 if(copy($oldStyleSource, $source)) {
140                                         // delete the old
141                                         if(!unlink($oldStyleSource)) {
142                                                 $GLOBALS['log']->warn("upload_file could not unlink [ {$oldStyleSource} ]");
143                                         }
144                                 } else {
145                                         $GLOBALS['log']->warn("upload_file could not copy [ {$oldStyleSource} ] to [ {$source} ]");
146                                 }
147                         }
148                 }
149                 
150                 $destination = $sugar_config['upload_dir'] . $new_id;
151                 if(!copy($source, $destination)) {
152                         $GLOBALS['log']->warn("upload_file could not copy [ {$source} ] to [ {$destination} ]");
153                 }
154         }
155
156         /**
157          * standard PHP file-upload security measures. all variables accessed in a global context
158          * @return bool True on success
159          */
160         function confirm_upload() {
161                 global $sugar_config;
162
163                 if(!is_uploaded_file($_FILES[$this->field_name]['tmp_name'])) {
164                         return false;
165                 } elseif($_FILES[$this->field_name]['size'] > $sugar_config['upload_maxsize']) {
166                         die("ERROR: uploaded file was too big: max filesize: {$sugar_config['upload_maxsize']}");
167                 }
168
169                 if(!is_writable($sugar_config['upload_dir'])) {
170                         die("ERROR: cannot write to directory: {$sugar_config['upload_dir']} for uploads");
171                 }
172
173                 $this->mime_type =$this->getMime($_FILES[$this->field_name]);
174                 $this->stored_file_name = $this->create_stored_filename();
175                 $this->temp_file_location = $_FILES[$this->field_name]['tmp_name'];
176
177                 return true;
178         }
179
180         function getMimeSoap($filename){
181
182                 if( function_exists( 'ext2mime' ) )
183                 {
184                         $mime = ext2mime($filename);
185                 }
186                 else
187                 {
188                         $mime = ' application/octet-stream';
189                 }
190                 return $mime;
191
192         }
193         function getMime(&$_FILES_element)
194         {
195
196                 $filename = $_FILES_element['name'];
197
198                 if( $_FILES_element['type'] )
199                 {
200                         $mime = $_FILES_element['type'];
201                 }
202                 elseif( function_exists( 'mime_content_type' ) )
203                 {
204                         $mime = mime_content_type( $_FILES_element['tmp_name'] );
205                 }
206                 elseif( function_exists( 'ext2mime' ) )
207                 {
208                         $mime = ext2mime( $_FILES_element['name'] );
209                 }
210                 else
211                 {
212                         $mime = ' application/octet-stream';
213                 }
214                 return $mime;
215         }
216
217         /**
218          * gets note's filename
219          * @return string
220          */
221         function get_stored_file_name() {
222                 return $this->stored_file_name;
223         }
224
225         /**
226          * creates a file's name for preparation for saving
227          * @return string
228          */
229         function create_stored_filename() {
230                 global $sugar_config;
231                 
232                 if(!$this->use_soap) {
233                         $stored_file_name = $_FILES[$this->field_name]['name'];
234                         $this->original_file_name = $stored_file_name;
235                         
236                         /**
237                          * cn: bug 8056 - windows filesystems and IIS do not like utf8.  we are forced to urlencode() to ensure that
238                          * the file is linkable from the browser.  this will stay broken until we move to a db-storage system
239                          */
240                         if(is_windows()) {
241                                 // create a non UTF-8 name encoding
242                                 // 176 + 36 char guid = windows' maximum filename length
243                                 $end = (strlen($stored_file_name) > 176) ? 176 : strlen($stored_file_name);
244                                 $stored_file_name = substr($stored_file_name, 0, $end);
245                                 $this->original_file_name = $_FILES[$this->field_name]['name'];
246                         }
247                 } else {
248                         $stored_file_name = $this->stored_file_name;
249                         $this->original_file_name = $stored_file_name;
250                 }
251                 
252         $ext_pos = strrpos($stored_file_name, ".");
253         if($ext_pos !== false)
254                         $this->file_ext = substr($stored_file_name, $ext_pos + 1);
255         // cn: bug 6347 - fix file extension detection 
256         foreach($sugar_config['upload_badext'] as $badExt) {
257             if(strtolower($this->file_ext) == strtolower($badExt)) {
258                 $stored_file_name .= ".txt";
259                 $this->file_ext="txt";
260                 break; // no need to look for more
261             }
262         }
263                 return $stored_file_name;
264         }
265
266         /**
267          * moves uploaded temp file to permanent save location
268          * @param string bean_id ID of parent bean
269          * @return bool True on success
270          */
271         function final_move($bean_id) {
272                 global $sugar_config;
273
274         $destination = clean_path($this->get_upload_path($bean_id));
275         if($this->use_soap) {
276                 $fp = sugar_fopen($destination, 'wb');
277                 if(!fwrite($fp, $this->file)){
278                         die("ERROR: can't save file to $destination");
279                 }
280                 fclose($fp);
281                 } else {
282                         if(!move_uploaded_file($_FILES[$this->field_name]['tmp_name'], $destination)) {
283                                 die("ERROR: can't move_uploaded_file to $destination. You should try making the directory writable by the webserver");
284                         }
285                 }
286                 return true;
287         }
288         
289         function upload_doc(&$bean, $bean_id, $doc_type, $file_name, $mime_type){
290         
291                 if(!empty($doc_type)&&$doc_type!='Sugar') {
292                         global $sugar_config;
293                 $destination = clean_path($this->get_upload_path($bean_id));
294                 sugar_rename($destination, str_replace($bean_id, $bean_id.'_'.$file_name, $destination));
295                 $new_destination = clean_path($this->get_upload_path($bean_id.'_'.$file_name));
296                             
297                     try{
298                 $this->api = ExternalAPIFactory::loadAPI($doc_type);
299
300                 if ( isset($this->api) && $this->api !== false ) {
301                     $result = $this->api->uploadDoc(
302                         $bean,
303                         $new_destination,
304                         $file_name,
305                         $mime_type
306                         );
307                 } else {
308                     $result['success'] = FALSE;
309                     // FIXME: Translate
310                     $GLOBALS['log']->error("Could not load the requested API (".$doc_type.")");
311                     $result['errorMessage'] = 'Could not find a proper API';
312                 }
313                 unlink($new_destination);
314             }catch(Exception $e){
315                 $result['success'] = FALSE;
316                 $result['errorMessage'] = $e->getMessage();
317                 $GLOBALS['log']->error("Caught exception: (".$e->getMessage().") ");
318             }
319             if ( !$result['success'] ) {
320                 sugar_rename($new_destination, str_replace($bean_id.'_'.$file_name, $bean_id, $new_destination));
321                 $bean->doc_type = 'Sugar';
322                 // FIXME: Translate
323                 if ( ! is_array($_SESSION['user_error_message']) ) 
324                     $_SESSION['user_error_message'] = array(); 
325
326                 $error_message = isset($result['errorMessage']) ? $result['errorMessage'] : $GLOBALS['app_strings']['ERR_EXTERNAL_API_SAVE_FAIL'];
327                 $_SESSION['user_error_message'][] = $error_message;
328
329             }
330         }
331         }
332
333         /**
334          * returns the path with file name to save an uploaded file
335          * @param string bean_id ID of the parent bean
336          * @return string
337          */
338         function get_upload_path($bean_id) {
339                 global $sugar_config;
340                 $file_name = $bean_id;
341                 
342                 // cn: bug 8056 - mbcs filename in urlencoding > 212 chars in Windows fails
343                 $end = (strlen($file_name) > 212) ? 212 : strlen($file_name);
344                 $ret_file_name = substr($file_name, 0, $end);
345                 
346                 return $sugar_config['upload_dir'].$ret_file_name;
347         }
348
349         /**
350          * deletes a file
351          * @param string bean_id ID of the parent bean
352          * @param string file_name File's name
353          */
354         function unlink_file($bean_id,$file_name) {
355                 global $sugar_config;
356         return unlink($sugar_config['upload_dir'].$bean_id.$file_name);
357     }
358 }
359 ?>