Add API to upload a patched build for a custom A/B testing
[WebKit.git] / Websites / perf.webkit.org / public / include / uploaded-file-helpers.php
1 <?php
2
3 define('MEGABYTES', 1024 * 1024);
4
5 function format_uploaded_file($file_row)
6 {
7     return array(
8         'id' => $file_row['file_id'],
9         'size' => $file_row['file_size'],
10         'createdAt' => Database::to_js_time($file_row['file_created_at']),
11         'mime' => $file_row['file_mime'],
12         'filename' => $file_row['file_filename'],
13         'author' => $file_row['file_author'],
14         'sha256' => $file_row['file_sha256']);
15 }
16
17 function uploaded_file_path_for_row($file_row)
18 {
19     return config_path('uploadDirectory', $file_row['file_id'] . $file_row['file_extension']);
20 }
21
22 function validate_uploaded_file($field_name)
23 {
24     if (array_get($_SERVER, 'CONTENT_LENGTH') && empty($_POST) && empty($_FILES))
25         exit_with_error('FileSizeLimitExceeded');
26
27     if (!is_dir(config_path('uploadDirectory', '')))
28         exit_with_error('NotSupported');
29
30     $input_file = array_get($_FILES, $field_name);
31     if (!$input_file)
32         exit_with_error('NoFileSpecified');
33
34     if ($input_file['error'] == UPLOAD_ERR_INI_SIZE || $input_file['error'] == UPLOAD_ERR_FORM_SIZE)
35         exit_with_error('FileSizeLimitExceeded');
36
37     if ($input_file['error'] != UPLOAD_ERR_OK)
38         exit_with_error('FailedToUploadFile', array('name' => $input_file['name'], 'error' => $input_file['error']));
39
40     if (config('uploadFileLimitInMB') * MEGABYTES < $input_file['size'])
41         exit_with_error('FileSizeLimitExceeded');
42
43     return $input_file;
44 }
45
46 function query_total_file_size($db, $user)
47 {
48     if ($user)
49         $count_result = $db->query_and_fetch_all('SELECT sum(file_size) as "sum" FROM uploaded_files WHERE file_deleted_at IS NULL AND file_author = $1', array($user));
50     else
51         $count_result = $db->query_and_fetch_all('SELECT sum(file_size) as "sum" FROM uploaded_files WHERE file_deleted_at IS NULL AND file_author IS NULL');
52     if (!$count_result)
53         return FALSE;
54     return intval($count_result[0]["sum"]);
55 }
56
57 function create_uploaded_file_from_form_data($input_file)
58 {
59     $file_sha256 = hash_file('sha256', $input_file['tmp_name']);
60     if (!$file_sha256)
61         exit_with_error('FailedToComputeSHA256');
62
63     $matches = array();
64     $file_extension = null;
65     if (preg_match('/(\.[a-zA-Z0-9]{1,5}){1,2}$/', $input_file['name'], $matches)) {
66         $file_extension = $matches[0];
67         assert(strlen($file_extension) <= 16);
68     }
69
70     return array(
71         'author' => remote_user_name(),
72         'filename' => $input_file['name'],
73         'extension' => $file_extension,
74         'mime' => $input_file['type'], // Sanitize MIME types.
75         'size' => $input_file['size'],
76         'sha256' => $file_sha256
77     );
78 }
79
80 function upload_file_in_transaction($db, $input_file, $remote_user, $additional_work = NULL)
81 {
82     // FIXME: Cleanup old files.
83
84     if (config('uploadUserQuotaInMB') * MEGABYTES - query_total_file_size($db, $remote_user) < $input_file['size'])
85         exit_with_error('FileSizeQuotaExceeded');
86
87     $uploaded_file = create_uploaded_file_from_form_data($input_file);
88
89     $db->begin_transaction();
90     $file_row = $db->select_or_insert_row('uploaded_files', 'file',
91         array('sha256' => $uploaded_file['sha256'], 'deleted_at' => null), $uploaded_file, '*');
92     if (!$file_row)
93         exit_with_error('FailedToInsertFileData');
94
95     // A concurrent session may have inserted another file.
96     if (config('uploadUserQuotaInMB') * MEGABYTES < query_total_file_size($db, $remote_user)) {
97         $db->rollback_transaction();
98         exit_with_error('FileSizeQuotaExceeded');
99     }
100
101     if ($additional_work) {
102         $error = $additional_work($db, $file_row);
103         if ($error) {
104             $db->rollback_transaction();
105             exit_with_error($error['status'], $error);
106         }
107     }
108
109     $new_path = uploaded_file_path_for_row($file_row);
110     if (!move_uploaded_file($input_file['tmp_name'], $new_path)) {
111         $db->rollback_transaction();
112         exit_with_error('FailedToMoveUploadedFile');
113     }
114
115     $db->commit_transaction();
116
117     return format_uploaded_file($file_row);
118 }
119
120 ?>