| 1 | <?php |
|---|
| 2 | require_once(IA_ROOT_DIR . "common/db/attachment.php"); |
|---|
| 3 | |
|---|
| 4 | // Validates an attachment struct. |
|---|
| 5 | function attachment_validate($att) { |
|---|
| 6 | $errors = array(); |
|---|
| 7 | |
|---|
| 8 | // FIXME How to handle this? |
|---|
| 9 | log_assert(is_array($att), "You didn't even pass an array"); |
|---|
| 10 | |
|---|
| 11 | if (!is_normal_page_name(getattr($att, 'page', ''))) { |
|---|
| 12 | $errors['page'] = 'Nume de pagina invalid.'; |
|---|
| 13 | } |
|---|
| 14 | |
|---|
| 15 | if (!is_attachment_name(getattr($att, 'name', ''))) { |
|---|
| 16 | $errors['page'] = 'Nume de pagina invalid.'; |
|---|
| 17 | } |
|---|
| 18 | |
|---|
| 19 | if (!is_user_id(getattr($att, 'user_id'))) { |
|---|
| 20 | $errors['user_id'] = 'ID de utilizator invalid'; |
|---|
| 21 | } |
|---|
| 22 | |
|---|
| 23 | if (!is_string(getattr($att, 'mime_type', 'text/plain'))) { |
|---|
| 24 | $errors['mime_type'] = 'Bad mime type'; |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | // NOTE: missing timestamp is OK!!! |
|---|
| 28 | // It stands for 'current moment'. |
|---|
| 29 | if (!is_db_date(getattr($att, 'timestamp', db_date_format()))) { |
|---|
| 30 | $errors['timestamp'] = 'Timestamp invalid.'; |
|---|
| 31 | } |
|---|
| 32 | |
|---|
| 33 | return $errors; |
|---|
| 34 | } |
|---|
| 35 | |
|---|
| 36 | // Get a file's mime type. |
|---|
| 37 | function get_mime_type($filename) { |
|---|
| 38 | if (function_exists("finfo_open")) { |
|---|
| 39 | // FIXME: cache. |
|---|
| 40 | $finfo = finfo_open(FILEINFO_MIME); |
|---|
| 41 | |
|---|
| 42 | log_assert($finfo !== false, |
|---|
| 43 | 'fileinfo is active but finfo_open() failed'); |
|---|
| 44 | |
|---|
| 45 | $res = finfo_file($finfo, $filename); |
|---|
| 46 | finfo_close($finfo); |
|---|
| 47 | log_print('get_mime_type('.$filename.'): finfo yields '.$res); |
|---|
| 48 | return $res; |
|---|
| 49 | } |
|---|
| 50 | if (function_exists("mime_content_type")) { |
|---|
| 51 | $res = @mime_content_type($filename); |
|---|
| 52 | if ($res !== false) { |
|---|
| 53 | return $res; |
|---|
| 54 | } |
|---|
| 55 | } |
|---|
| 56 | log_warn("fileinfo extension failed, defaulting mime type to application/octet-stream."); |
|---|
| 57 | return "application/octet-stream"; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | // Resize 2D coordinates according to 'textual' instructions |
|---|
| 61 | // Given a (width, height) pair, resize it (compute new pair) according to |
|---|
| 62 | // resize instructions. |
|---|
| 63 | // |
|---|
| 64 | // Resize instructions may be: |
|---|
| 65 | // # example # description |
|---|
| 66 | // 100x100 Keep aspect ratio, resize as to fit a 100x100 box. |
|---|
| 67 | // Coordinates are not enlarged if they already fit the given box. |
|---|
| 68 | // @50x86 Ignore aspect ratio, resize to exactly 50x86. |
|---|
| 69 | // 50% Scale dimensions; only integer percentages allowed. |
|---|
| 70 | // L100x100 Layout resize: same as 100x100 only it will enlarge coordinates |
|---|
| 71 | // if coordinates already fit target box. Use this where layout |
|---|
| 72 | // matters. |
|---|
| 73 | // |
|---|
| 74 | // Returns 2-element array: (width, height) or null if invalid format |
|---|
| 75 | function resize_coordinates($width, $height, $resize) { |
|---|
| 76 | // 100x100 or @100x100 or L100x100 |
|---|
| 77 | if (preg_match('/^([\@L]?)([0-9]+)x([0-9]+)$/i', $resize, $matches)) { |
|---|
| 78 | $flag = strtolower($matches[1]); |
|---|
| 79 | $boxw = (float)$matches[2]; |
|---|
| 80 | $boxh = (float)$matches[3]; |
|---|
| 81 | |
|---|
| 82 | if ('@' == $flag) { |
|---|
| 83 | // exact fit, ignore aspect ratio |
|---|
| 84 | return array($boxw, $boxh); |
|---|
| 85 | } |
|---|
| 86 | else { |
|---|
| 87 | // keep aspect ratio |
|---|
| 88 | |
|---|
| 89 | $layout = ('l' == $flag); |
|---|
| 90 | $ratio = 1.0; |
|---|
| 91 | if ($width > $boxw || $layout) { |
|---|
| 92 | $ratio = $boxw / $width; |
|---|
| 93 | } |
|---|
| 94 | if ($height * $ratio > $boxh) { |
|---|
| 95 | $ratio = $boxh / $height; |
|---|
| 96 | } |
|---|
| 97 | |
|---|
| 98 | return array(floor($ratio * $width), floor($ratio * $height)); |
|---|
| 99 | } |
|---|
| 100 | } |
|---|
| 101 | // zoom: 50% |
|---|
| 102 | elseif (preg_match('/^([0-9]+)%$/', $resize, $matches)) { |
|---|
| 103 | $ratio = (float)$matches[1] / 100; |
|---|
| 104 | return array(floor($ratio * $width), floor($ratio * $height)); |
|---|
| 105 | } |
|---|
| 106 | // invalid format |
|---|
| 107 | else { |
|---|
| 108 | return null; |
|---|
| 109 | } |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | function is_textfile($mime_type) { |
|---|
| 113 | return substr($mime_type, 0, 5) == "text/"; |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | function dos_to_unix($file_path) { |
|---|
| 117 | system("dos2unix ".$file_path); |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | function is_grader_testfile($file_name) { |
|---|
| 121 | $pattern = '/^grader_test(\d)*\.(ok|in)$/'; |
|---|
| 122 | if (preg_match($pattern, $file_name) == false) { |
|---|
| 123 | return false; |
|---|
| 124 | } else { |
|---|
| 125 | return true; |
|---|
| 126 | } |
|---|
| 127 | } |
|---|
| 128 | |
|---|
| 129 | function is_problem_page($page_name) { |
|---|
| 130 | $pattern = '/^problema\/' . IA_RE_TASK_ID . '$/'; |
|---|
| 131 | if (preg_match($pattern, $page_name) == false) { |
|---|
| 132 | return false; |
|---|
| 133 | } else { |
|---|
| 134 | return true; |
|---|
| 135 | } |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | function add_ending_newline($file_path) { |
|---|
| 139 | $content = file_get_contents($file_path); |
|---|
| 140 | if ($content[strlen($content) - 1] != "\n") { |
|---|
| 141 | $content .= "\n"; |
|---|
| 142 | file_put_contents($file_path, $content); |
|---|
| 143 | return true; |
|---|
| 144 | } |
|---|
| 145 | return false; |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | /** |
|---|
| 149 | * Resizes an image whose filepath is given by the parameters into a new |
|---|
| 150 | * location specified by the other parameters |
|---|
| 151 | * |
|---|
| 152 | * Returns whether or not the image has been successfully resized |
|---|
| 153 | * Note that it returns false if the image doesn't have a known file-type |
|---|
| 154 | * |
|---|
| 155 | * The $new_filepath parameter if ommited or given as null will result in the |
|---|
| 156 | * image being outputted directly to the client |
|---|
| 157 | * |
|---|
| 158 | * @param array $image_info An array containing information about the |
|---|
| 159 | * original image: width, height, mime-type |
|---|
| 160 | * @param string $filepath |
|---|
| 161 | * @param array $new_image_info An array containing the new width and |
|---|
| 162 | * height |
|---|
| 163 | * @param string $new_filepath |
|---|
| 164 | * @return bool |
|---|
| 165 | */ |
|---|
| 166 | function image_resize($image_info, $filepath, $new_image_info, |
|---|
| 167 | $new_filepath = null) { |
|---|
| 168 | list($image_width, $image_height, $image_type, $image_attribute) = $image_info; |
|---|
| 169 | list($new_image_width, $new_image_height) = $new_image_info; |
|---|
| 170 | |
|---|
| 171 | switch ($image_type) { |
|---|
| 172 | case IMAGETYPE_GIF: |
|---|
| 173 | // NOTE: animated GIFs become static. Only the first frame is saved |
|---|
| 174 | // Seems like a good thing anyway |
|---|
| 175 | $image = imagecreatefromgif($filepath); |
|---|
| 176 | $image_resized = imagecreate($new_image_width, $new_image_height); |
|---|
| 177 | // reset palette and transparent color to that of the original file |
|---|
| 178 | $trans_col = imagecolortransparent($image); |
|---|
| 179 | imagepalettecopy($image_resized, $image); |
|---|
| 180 | if ($trans_col != -1) { |
|---|
| 181 | imagefill($image_resized, 0, 0, $trans_col); |
|---|
| 182 | } |
|---|
| 183 | imagecolortransparent($image_resized, $trans_col); |
|---|
| 184 | imagecopyresampled($image_resized, $image, 0, 0, 0, 0, |
|---|
| 185 | $new_image_width, $new_image_height, $image_width, |
|---|
| 186 | $image_height); |
|---|
| 187 | |
|---|
| 188 | if ($new_filepath != null) { |
|---|
| 189 | return imagegif($image_resized, $new_filepath); |
|---|
| 190 | } |
|---|
| 191 | return imagegif($image_resized); |
|---|
| 192 | |
|---|
| 193 | case IMAGETYPE_JPEG: |
|---|
| 194 | $image = imagecreatefromjpeg($filepath); |
|---|
| 195 | $image_resized = imagecreatetruecolor($new_image_width, |
|---|
| 196 | $new_image_height); |
|---|
| 197 | imagecopyresampled($image_resized, $image, 0, 0, 0, 0, |
|---|
| 198 | $new_image_width, $new_image_height, $image_width, |
|---|
| 199 | $image_height); |
|---|
| 200 | |
|---|
| 201 | if ($new_filepath != null) { |
|---|
| 202 | return imagejpeg($image_resized, $new_filepath); |
|---|
| 203 | } |
|---|
| 204 | return imagejpeg($image_resized); |
|---|
| 205 | |
|---|
| 206 | case IMAGETYPE_PNG: |
|---|
| 207 | $image = imagecreatefrompng($filepath); |
|---|
| 208 | $image_resized = imagecreatetruecolor($new_image_width, |
|---|
| 209 | $new_image_height); |
|---|
| 210 | // turn off the alpha blending to keep the alpha channel |
|---|
| 211 | imagealphablending($image_resized, false); |
|---|
| 212 | // allocate transparent color |
|---|
| 213 | $col = imagecolorallocatealpha($image_resized, 0, 0, 0, 127); |
|---|
| 214 | // fill the image with the new color |
|---|
| 215 | imagefilledrectangle($image_resized, 0, 0, $new_image_width, |
|---|
| 216 | $new_image_height, $col); |
|---|
| 217 | imagecopyresampled($image_resized, $image, 0, 0, 0, 0, |
|---|
| 218 | $new_image_width, $new_image_height, $image_width, |
|---|
| 219 | $image_height); |
|---|
| 220 | imagesavealpha($image_resized, true); |
|---|
| 221 | if ($new_filepath != null) { |
|---|
| 222 | return imagepng($image_resized, $new_filepath); |
|---|
| 223 | } |
|---|
| 224 | return imagepng($image_resized); |
|---|
| 225 | |
|---|
| 226 | default: |
|---|
| 227 | // unsupported image type |
|---|
| 228 | return false; |
|---|
| 229 | } |
|---|
| 230 | } |
|---|
| 231 | ?> |
|---|