Анимация
JavaScript
|
Главная Библионтека загрузка файлов ( Замечание Данный раздел главы предназначен скорее для ознакомления, нежели для применения в качестве точной инструкции по загрузке файлов. Он прекрасно демонстрирует, почему нам так удобно использовать PHP для программирования в Web. Организацию загрузки файлов в PHP мы подробно разберем в части V. Иногда бывает просто необходимо позволить пользователю не только заполнить текстовые поля формы и установить соответствующие переключатели, но также и указать несколько файлов, которые будут впоследствии загружены с компьютера пользо- Списки множественного выбора (multiple) В какой форме приходят данные сценарию, если был создан multiple-список? Очень просто: все произойдет так, будто есть не один, а несколько не-multiple-списков, все с одинаковым именем, и в каждом из которых выбрано по одному элементу. Иными словами, строка параметров, порожденная этим тэгом, будет выглядеть примерно так: имя=значение1&имя=значение2&...&имя=значениеN Кстати говоря, совершенно не уникальный случай - то, что с одним именем связано сразу несколько значений. Действительно, нам никто не мешает создавать и другие тэги с идентичными именами. Это часто делается, например, для переключателей-флажков: <input type=checkbox name=имя value="Один">Один<br> <input type=checkbox name=имя value="Два">Два<br> <input type=checkbox name=имя value="Три">Три<br> Если теперь пользователь установит сразу все флажки, то сценарию поступит строка (конечно, в URL-кодированном виде): имя=Один&имя=Два&имя=Три Из всего сказанного следует не очень утешительный вывод: при разборе строки параметров в сценарии мы не можем полагаться на то, что каждой переменной соответствует только одно значение. Нам придется учитывать, что их может быть не "один", а "много". А это очень неприятно с точки зрения программирования - особенно на Си. Попутно мы обнаружили, что любой multiple-список может быть представлен набором флажков (независимых переключателей), а любой не-miltiple - в виде нескольких радиокнопок. Так что, вообще говоря, тэг <select> - некоторое функциональное излишество, и с точки зрения сценария вполне может заменяться флажками и радиокнопками. вателя на сервер. Для этого в языке HTML предусмотрены специальные средства. Рассмотрим их подробнее. Формат данных В свое время я говорил, что все данные из формы при передаче их на сервер упаковываются в строку при помощи символов ?, & и =. Легко видеть, что при загрузке файлов такой способ, хотя и приемлем, но будет существенно увеличивать размер передаваемой информации. Действительно, ведь большинство файлов - бинарные, а мы знаем, что при URL-кодировании данные таких файлов сильно "распухают" - примерно в три раза (например, простой нулевой байт при URL-кодировании превратится в %00). Это сильно замедлит передачу и увеличит нагрузку на канал. И вот, отчасти специально для решения указанной проблемы был изобретен другой формат передачи данных, отличный от того, который мы до сих пор рассматривали. В нем уже не используются пресловутые символы ? и & . Кроме того, похоже, в случае применения такого формата передачи может быть задействован только метод post, но не метод get. Нас это вполне устроит - ведь файлы обгчно большие, и доставлять их через GET вряд ли разумно... Если нужно указать браузеру, что в какой-то форме следует применять другой формат передачи, следует в соответствующем тэге <form> задать атрибут enctype=multipart/form-data. (Кстати говоря, если этот атрибут не указан, то форма считается обычной, что эквивалентно enctype=application/x-www-form-urlencoded - именно так обозначается привычный нам формат передачи.) После этого данные, поступившие от нашей формы, будут выглядеть как несколько блоков информации (по одному на элемент формы). Каждый такой блок очень напоминает HTTP-формат "заголовки-данные", используемый при традиционном формате передачи. Выглядит блок примерно так (\n, как всегда, обозначает символ перевода строки): -----------------ИДентификатор начала\n Content-Disposition: form-data; name="имя"\n значение\n Например, пусть у нас есть форма: i Листинг 3.7. Multipart-форма <form action=... enctype=multipart/form-data method=post> Name: <input type=text name="Name" value="Мое имя"><Ьг> Box: <input type=checkbox name="Box" value=1 checked><br> Area: <input type=textarea name="Area">Это какой-то текст</textarea><br> <input type=submit> Стандарт протокола HTTP говорит нам, что идентификатор начала также должен быть доступен через одну из переменных окружения. Но я не помню и не хочу знать ее название - сейчас объясню, почему. Некоторые браузеры (особенно старые) путают этот идентификатор и присылают его неправильно - с двумя предшествующими минусами (а остальные - без них), так что сценарии, не рассчитывающие на такой подвох, перестанут работать. Никогда не полагайтесь на эту переменную окружения (даже если узнаете, как она называется)! Вместо этого читайте последовательность символов до первого перевода строки и воспринимайте именно ее как разделитель. Далее алгоритм разбора должен быть следующим: в цикле мы пропускаем символы идентификатора и перевода строки, извлекаем подстроку имя="что-то" (не обращая внимания на Content-Disposition), дожидаемся двух символов перевода строки и затем считаем значением соответствующего поля все те данные, которые размещены до строки \nИдентификатор (или же до конца, если такой строки больше нет). Как видите, все довольно просто. </form> Данные, поступившие по нажатии кнопки submit на сервер, будут иметь следующий вид: ----------------127462537625367\n Content-Disposition: form-data; name="Name"\n Мое имя\п ----------------127462537625367\n Content-Disposition: form-data; name="Box"\n \n 1\n ----------------127462537625367\n Content-Disposition: form-data; name="Area"\n Это какой-то текст\n Заметьте, что несколько дефисов и число (которое мы ранее назвали Идентификатор начала) предшествуют каждому блоку. Более того, строка из дефисов и этого числа служит своеобразным маркером, который разделяет блоки. Очевидно, эта строка должна быть уникальной во всех данных. Именно так ее и формирует браузер. Правда, сказанное означает, что сегодня идентификатор будет одним, а завтра, возможно, совсем другим. Так что нам придется, прежде чем анализировать данные, считать этот идентификатор в буфер (им будет последовательность символов до первого символа \n). 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 [ 20 ] 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |