line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Для разрешения upload-а нужно в директорию со скриптом поместить файл с |
2
|
|
|
|
|
|
|
# именем ".can_upload". В противном случае upload запрещаеся. |
3
|
|
|
|
|
|
|
# Если же этот файл задан, то делается попытка прочитать из него параметры: |
4
|
|
|
|
|
|
|
# dir=имя_директории для закачки |
5
|
|
|
|
|
|
|
# maxsize=максимальный_размер закачиваемого файла |
6
|
|
|
|
|
|
|
# В любом случае, по окончание работы скрипта закачанные файлы удаляются |
7
|
|
|
|
|
|
|
# (если только они не были перемещены скриптом в другое место). |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# TODO: |
10
|
|
|
|
|
|
|
# 3. Попробовать решить проблему экспорта |
11
|
|
|
|
|
|
|
# 4. Имена временных файлов должны быть совместимы с Маком. |
12
|
|
|
|
|
|
|
# 5. Поддержка undef в Serialize + предупреждения. |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
package CGI::WebIn; |
15
|
1
|
|
|
1
|
|
6640
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
473
|
|
16
|
|
|
|
|
|
|
our $VERSION = '2.03'; |
17
|
|
|
|
|
|
|
our @EXPORT=qw( |
18
|
|
|
|
|
|
|
%IN |
19
|
|
|
|
|
|
|
%GET |
20
|
|
|
|
|
|
|
%POST |
21
|
|
|
|
|
|
|
%COOKIES |
22
|
|
|
|
|
|
|
SetCookie |
23
|
|
|
|
|
|
|
DropCookie |
24
|
|
|
|
|
|
|
); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
####################### Константы, управляющие работой ##################### |
28
|
|
|
|
|
|
|
our $CANUPL_FILE = ".can_upload"; # имя файла, разрешающего закачку |
29
|
|
|
|
|
|
|
our $MULTICHUNK_SIZE = 20000; # длина блока считывания STDIN-а |
30
|
|
|
|
|
|
|
our $MAX_ARRAY_IDX = 10000; # максимально возможный индекс N в a[N] |
31
|
|
|
|
|
|
|
our $uniq_tempnam = 0; # temp files counter |
32
|
|
|
|
|
|
|
our @TempFiles = (); # all temp files (to delete after end) |
33
|
|
|
|
|
|
|
our @Errors = (); # all query parsing errors |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Настройки сериализации. |
36
|
|
|
|
|
|
|
# Некоторые внутренние настроечные переменные. Фактически, они используются |
37
|
|
|
|
|
|
|
# в качестве констант. Лучше всего их никогда не трогать. Эти константы |
38
|
|
|
|
|
|
|
# должны состоять из одного символа! |
39
|
|
|
|
|
|
|
our $Div1 = "."; # ALWAYS should be one nondigit!!! |
40
|
|
|
|
|
|
|
our $Div2 = "."; # may be the same as $Div1 |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
####################### Преременные с данными браузера ##################### |
44
|
|
|
|
|
|
|
our %IN = (); # Данные формы |
45
|
|
|
|
|
|
|
our %GET = (); # Данные GET |
46
|
|
|
|
|
|
|
our %POST = (); # Данные POST |
47
|
|
|
|
|
|
|
our %COOKIES = (); # Все пришедшие Cookies |
48
|
|
|
|
|
|
|
our %IMPORT_MOD = (); # Модули, затребовавшие импорт переменных (ключи) |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# void _reparseAll() |
52
|
|
|
|
|
|
|
# Parses all the input data. |
53
|
|
|
|
|
|
|
sub _reparseAll { |
54
|
1
|
50
|
|
1
|
|
5
|
if($ENV{QUERY_STRING}) { |
55
|
0
|
|
|
|
|
0
|
_parseURLEnc($ENV{QUERY_STRING},"get"); |
56
|
|
|
|
|
|
|
} |
57
|
1
|
50
|
|
|
|
5
|
if(uc($ENV{REQUEST_METHOD}) eq "POST") { |
58
|
0
|
0
|
0
|
|
|
0
|
if(exists($ENV{'CONTENT_TYPE'}) && $ENV{'CONTENT_TYPE'}=~m|^\s*multipart/form-data|i) { |
59
|
0
|
|
|
|
|
0
|
_parseMultipart(); |
60
|
|
|
|
|
|
|
} else { |
61
|
0
|
|
|
|
|
0
|
read(STDIN,my $data,$ENV{CONTENT_LENGTH}); |
62
|
0
|
|
|
|
|
0
|
_parseURLEnc($data,"post"); |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
} |
65
|
1
|
50
|
33
|
|
|
8
|
if($ENV{HTTP_COOKIE} || $ENV{COOKIE}) { |
66
|
0
|
|
|
|
|
0
|
_parseCookies(); |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
# use Data::Dumper; print "".Dumper(\%IN)." "; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# void import(...) |
73
|
|
|
|
|
|
|
# Called on 'use'. |
74
|
|
|
|
|
|
|
sub import |
75
|
1
|
|
|
1
|
|
7
|
{ my ($pkg, $opt)=@_; |
76
|
1
|
|
|
|
|
3
|
my $caller = caller(); |
77
|
1
|
50
|
|
|
|
3
|
export_vars($opt, $caller) if $opt; |
78
|
1
|
|
|
1
|
|
7
|
no strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
748
|
|
79
|
1
|
|
|
|
|
3
|
foreach (@EXPORT) { |
80
|
6
|
|
|
|
|
25
|
my ($type, $name) = /^([%@\$]?)(.*)$/s; |
81
|
6
|
100
|
|
|
|
19
|
if ($type eq '%') { |
|
|
50
|
|
|
|
|
|
82
|
4
|
|
|
|
|
4
|
*{$caller."::".$name} = \%{$name}; |
|
4
|
|
|
|
|
17
|
|
|
4
|
|
|
|
|
9
|
|
83
|
|
|
|
|
|
|
} elsif ($type eq '') { |
84
|
2
|
|
|
|
|
1
|
*{$caller."::".$name} = \&{$name}; |
|
2
|
|
|
|
|
1793
|
|
|
2
|
|
|
|
|
8
|
|
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# Deletes temporary files if present. |
91
|
|
|
|
|
|
|
sub END |
92
|
1
|
50
|
|
1
|
|
185
|
{ map { unlink($_) } @TempFiles if @TempFiles; |
|
0
|
|
|
|
|
0
|
|
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# list of string GetErrors() |
96
|
|
|
|
|
|
|
# Returns all errors collected while parsing the form input data |
97
|
|
|
|
|
|
|
# (for example, too large autoarray index). |
98
|
|
|
|
|
|
|
sub GetErrors { |
99
|
0
|
|
|
0
|
0
|
0
|
return @Errors; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# Encoding and decoding. |
104
|
1
|
|
|
1
|
0
|
309
|
sub URLEncode { my ($s)=@_; $s=~s{([^-_A-Za-z0-9./])}{sprintf("%%%02X", ord $1)}sge; return $s } |
|
1
|
|
|
|
|
11
|
|
|
233
|
|
|
|
|
750
|
|
|
1
|
|
|
|
|
5
|
|
105
|
1
|
|
|
1
|
0
|
6
|
sub URLDecode { my ($s)=@_; $s=~tr/+/ /; $s=~s/%([0-9A-Fa-f]{2})/chr(hex($1))/esg; return $s } |
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
6
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
2
|
|
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
my %CODE = ( |
109
|
|
|
|
|
|
|
'export_vars' => <<'END_OF_FUNC', |
110
|
|
|
|
|
|
|
# void export_vars(sting $options, string $toPkg) |
111
|
|
|
|
|
|
|
# Export EGPC-variables from %GET, %POST etc. |
112
|
|
|
|
|
|
|
sub export_vars |
113
|
|
|
|
|
|
|
{ my ($opt, $to)=@_; |
114
|
|
|
|
|
|
|
if(!scalar(@_)) { |
115
|
|
|
|
|
|
|
# Вызов без параметров - обойти и экспортировать во все модули-клиенты |
116
|
|
|
|
|
|
|
while(my ($mod,$opt)=each(%IMPORT_MOD)) { |
117
|
|
|
|
|
|
|
export_vars($opt,$mod); |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
} else { |
120
|
|
|
|
|
|
|
# Вызов с параметрами - экспорт переменных только в укакзанный модуль |
121
|
|
|
|
|
|
|
return if !$opt; |
122
|
|
|
|
|
|
|
$opt="gpces" if lc($opt) eq "a" || $opt eq "1"; |
123
|
|
|
|
|
|
|
# Сохраняем информацию о том, что модуль "хочет" экспортирования и |
124
|
|
|
|
|
|
|
# в дальнейшем. Например, при вызове SetCookie() соответствующая |
125
|
|
|
|
|
|
|
# переменная создастся не только в %COOKIES, но и во всех модулях. |
126
|
|
|
|
|
|
|
$IMPORT_MOD{$to}=$opt; |
127
|
|
|
|
|
|
|
# Экспортируем еще не существующие переменные |
128
|
|
|
|
|
|
|
no strict; |
129
|
|
|
|
|
|
|
my $Bad=\%{$to."::"}; |
130
|
|
|
|
|
|
|
foreach my $op (split //,$opt) { |
131
|
|
|
|
|
|
|
$op=lc($op); |
132
|
|
|
|
|
|
|
my $Hash = |
133
|
|
|
|
|
|
|
$op eq "g" && \%GET || |
134
|
|
|
|
|
|
|
$op eq "p" && \%POST || |
135
|
|
|
|
|
|
|
$op eq "c" && \%COOKIES || |
136
|
|
|
|
|
|
|
$op eq "e" && \%ENV || next; |
137
|
|
|
|
|
|
|
while(my ($k,$v)=each(%$Hash)) { |
138
|
|
|
|
|
|
|
# не переписывать существующие переменные |
139
|
|
|
|
|
|
|
next if exists $Bad->{$k}; |
140
|
|
|
|
|
|
|
## BUGFIX 11.07.2002 v1.10: |
141
|
|
|
|
|
|
|
## разрешается применять только буквенно-цифровые имена, |
142
|
|
|
|
|
|
|
## раньше имена вида SomeModule::var приводили к дыре |
143
|
|
|
|
|
|
|
## в безопасности. |
144
|
|
|
|
|
|
|
next if $k=~/[^\w\d_]/s; |
145
|
|
|
|
|
|
|
*{$to."::".$k}=ref($v)? $Hash->{$k} : \$Hash->{$k}; |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
END_OF_FUNC |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
'_processPar' => <<'END_OF_FUNC', |
154
|
|
|
|
|
|
|
# void _processPar(string $key, string $value, string $type) |
155
|
|
|
|
|
|
|
# Добавляет пару $key=>$value в хэш %IN (с разбором многоуровневых хэшей), |
156
|
|
|
|
|
|
|
# а также в хэш %GET, %POST или %COOKIES, в зависимости от значения $type |
157
|
|
|
|
|
|
|
# (get, post, cookies соответственно). |
158
|
|
|
|
|
|
|
# Пустые скобки "{}" заменяются на значение "{$v}"! |
159
|
|
|
|
|
|
|
sub _processPar |
160
|
|
|
|
|
|
|
{ my ($k,$v,$type)=@_; |
161
|
|
|
|
|
|
|
return if !defined($k); |
162
|
|
|
|
|
|
|
$type=uc($type||"IN"); |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
## BUGFIX 12.07.2002 v1.10: |
165
|
|
|
|
|
|
|
## до этого было s/\r//sg, что неправильно работало на Маке. |
166
|
|
|
|
|
|
|
$v=~s/\x0d\x0a?|\x0a\x0d?/\n/sg if defined $v && !ref $v; |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# Проверяем вид "a{10}{20}" и заодно получаем первый ключ |
169
|
|
|
|
|
|
|
do { push @Errors, "$type: Unknown input field format '$k'"; return } if $k!~/^([^}{\[\]]+)/sg; |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
## Этап I: Получаем все индексы, обрамленные соотв. скобками. |
172
|
|
|
|
|
|
|
my @Ind = ([$1, '']); |
173
|
|
|
|
|
|
|
while(pos $k < length $k) { |
174
|
|
|
|
|
|
|
my ($i,$t); |
175
|
|
|
|
|
|
|
$k=~/\G |
176
|
|
|
|
|
|
|
\{ ( |
177
|
|
|
|
|
|
|
(?: |
178
|
|
|
|
|
|
|
[^}"']* | |
179
|
|
|
|
|
|
|
## BUGFIX 12.07.2002 v1.10: |
180
|
|
|
|
|
|
|
## нужно писать [^"\\], а не [^"]. |
181
|
|
|
|
|
|
|
## after slash ALWAYS must be any character. |
182
|
|
|
|
|
|
|
"(?:[^"\\]+|\\.)*" | |
183
|
|
|
|
|
|
|
'(?:[^'\\]+|\\.)*' |
184
|
|
|
|
|
|
|
) |
185
|
|
|
|
|
|
|
) \} |
186
|
|
|
|
|
|
|
/sxgc and do { $t=$Ind[-1][1]='HASH'; push @Ind, $i=[$1, ''] } |
187
|
|
|
|
|
|
|
or #### |
188
|
|
|
|
|
|
|
$k=~/\G |
189
|
|
|
|
|
|
|
\[ ( |
190
|
|
|
|
|
|
|
(?: |
191
|
|
|
|
|
|
|
[^]"']* | |
192
|
|
|
|
|
|
|
"(?:[^"\\]+|\\.)*" | |
193
|
|
|
|
|
|
|
'(?:[^'\\]+|\\.)*' |
194
|
|
|
|
|
|
|
)* |
195
|
|
|
|
|
|
|
) \] |
196
|
|
|
|
|
|
|
/sxgc and do { $t=$Ind[-1][1]='ARRAY'; push @Ind, $i=[$1, ''] } |
197
|
|
|
|
|
|
|
or ### |
198
|
|
|
|
|
|
|
do { push @Errors, "$type: Corrupted parameter '$k'"; return }; |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
if($i->[0] eq "" && defined $v) { |
201
|
|
|
|
|
|
|
# Заменяем пустой индекс БЕЗ КАВЫЧЕК на $v или -1 |
202
|
|
|
|
|
|
|
$i->[0] = $t eq 'HASH'? $v : ''; |
203
|
|
|
|
|
|
|
} else { |
204
|
|
|
|
|
|
|
# Убираем слэши перед кавычками, но только если строка была заковычена. |
205
|
|
|
|
|
|
|
$i->[0]=~s/^(['"])(.*)\1$/$2/sg |
206
|
|
|
|
|
|
|
and |
207
|
|
|
|
|
|
|
$i->[0]=~s/\\(['"\\])/$1/sg; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
# [0] содержит очередной индекс. |
211
|
|
|
|
|
|
|
# [1] содержит ТИП объекта, в котором этот индекс СОДЕРЖИТСЯ. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
# use Data::Dumper; print "".Dumper(\%IN)." "; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
## Этап II: заполняем хэши. К сожалению, приходится делать |
216
|
|
|
|
|
|
|
## цикл по всем хэшам и фактически делать одну работу несколько |
217
|
|
|
|
|
|
|
## раз, потому что где-то уже могут существовать полузаполненные |
218
|
|
|
|
|
|
|
## хэши. |
219
|
|
|
|
|
|
|
my @Outs=(\%IN); |
220
|
|
|
|
|
|
|
push @Outs, \%GET if lc($type) eq "get"; |
221
|
|
|
|
|
|
|
push @Outs, \%POST if lc($type) eq "post"; |
222
|
|
|
|
|
|
|
push @Outs, \%COOKIES if lc($type) eq "cookie"; |
223
|
|
|
|
|
|
|
foreach my $cur (@Outs) { |
224
|
|
|
|
|
|
|
foreach my $idx (@Ind) { |
225
|
|
|
|
|
|
|
# Текущий ключ и тип значения по этому ключу. |
226
|
|
|
|
|
|
|
my ($i,$t) = @$idx; |
227
|
|
|
|
|
|
|
# Получаем ссылку $r не то место, куда нужно записать значение. |
228
|
|
|
|
|
|
|
my $r; |
229
|
|
|
|
|
|
|
if(ref $cur eq 'HASH') { |
230
|
|
|
|
|
|
|
# Работаем с $cur как с хэшем. |
231
|
|
|
|
|
|
|
$r = \$cur->{$i}; |
232
|
|
|
|
|
|
|
} elsif(ref $cur eq 'ARRAY') { |
233
|
|
|
|
|
|
|
# Работаем с $cur как с массивом. |
234
|
|
|
|
|
|
|
# Индекс -1 означает "добавить в конец". |
235
|
|
|
|
|
|
|
$i = @$cur if $i eq ""; |
236
|
|
|
|
|
|
|
# Не-цифровые и слишком большие индексы не допускаются. |
237
|
|
|
|
|
|
|
do { push @Errors, "$type: Non-numeric index '$i' in '$k'"; return } if $i=~/[^\d]/s; |
238
|
|
|
|
|
|
|
do { push @Errors, "$type: Too large index '$i' in '$k'"; return } if $i>$MAX_ARRAY_IDX; |
239
|
|
|
|
|
|
|
$r = \$cur->[$i]; |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
# Если такого ключа еще нет, то в $$r будет undef. |
242
|
|
|
|
|
|
|
$$r = ($t eq 'HASH'? {} : $t eq 'ARRAY'? [] : '') if !defined $$r; |
243
|
|
|
|
|
|
|
# Проверка соответствия типов. |
244
|
|
|
|
|
|
|
if(ref($$r) ne $t) { |
245
|
|
|
|
|
|
|
push @Errors, "$type: Mismatched parameter type: key '$i' in '$k' later defined as ".(ref($$r)||"SCALAR").", not ".(!$t? "SCALAR" : $t eq 'HASH'? 'HASH' : 'ARRAY'); |
246
|
|
|
|
|
|
|
return; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
$$r = $v if !$t; |
249
|
|
|
|
|
|
|
$cur = $$r; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
END_OF_FUNC |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
'_parseURLEnc' => <<'END_OF_FUNC', |
257
|
|
|
|
|
|
|
# void _parseURLEnc(string $input, string $type) |
258
|
|
|
|
|
|
|
sub _parseURLEnc |
259
|
|
|
|
|
|
|
{ my ($tosplit,$type) = @_; |
260
|
|
|
|
|
|
|
my (@pairs) = split(/[&?]/,$tosplit); |
261
|
|
|
|
|
|
|
my ($param,$value); |
262
|
|
|
|
|
|
|
foreach (@pairs) { |
263
|
|
|
|
|
|
|
($param,$value) = split('=',$_,2); |
264
|
|
|
|
|
|
|
$param = URLDecode(defined($param)?$param:""); |
265
|
|
|
|
|
|
|
$value = URLDecode(defined($value)?$value:""); |
266
|
|
|
|
|
|
|
_processPar($param,$value,$type); |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
END_OF_FUNC |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
'tempnam' => <<'END_OF_FUNC', |
273
|
|
|
|
|
|
|
# string tempnam([string $Dir]) |
274
|
|
|
|
|
|
|
# Возвращает уникальное (используется PID и таймер) имя файла в директории, указанной в |
275
|
|
|
|
|
|
|
# параметрах. По умолчанию - в директории, указанной в переменной окружения TMP или TEMP, |
276
|
|
|
|
|
|
|
# или, в крайнем случае, в текущей. В конце работы скрипта все файлы, имеющие |
277
|
|
|
|
|
|
|
# имена, сгенерированные tempnam(), будут удалены! |
278
|
|
|
|
|
|
|
# Всегда возвращает полный путь к временному файлу. |
279
|
|
|
|
|
|
|
sub tempnam |
280
|
|
|
|
|
|
|
{ my ($dir)=@_; |
281
|
|
|
|
|
|
|
foreach my $cd ($dir,$ENV{TMP},$ENV{TEMP},"/tmp",".") { |
282
|
|
|
|
|
|
|
if(defined $cd && -d $cd && -w $cd) { $dir=$cd; last; } |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
my $nm=$dir."/".time()."-$$-".(++$uniq_tempnam).".tmp"; |
285
|
|
|
|
|
|
|
if($nm!~m{^[/\\]}) { |
286
|
|
|
|
|
|
|
require Cwd; |
287
|
|
|
|
|
|
|
$nm=Cwd::getcwd()."/".$nm; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
push(@TempFiles,$nm); |
290
|
|
|
|
|
|
|
return $nm; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
END_OF_FUNC |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
'_parseMultipart' => <<'END_OF_FUNC', |
296
|
|
|
|
|
|
|
# hash _readUplConf() |
297
|
|
|
|
|
|
|
# Читает конфигурационный файл, разрешающий или запрещающий |
298
|
|
|
|
|
|
|
# закачку в текущей директории. |
299
|
|
|
|
|
|
|
sub _readUplConf { |
300
|
|
|
|
|
|
|
open(local *F,"<$CANUPL_FILE") or return |
301
|
|
|
|
|
|
|
my %cfg=(); |
302
|
|
|
|
|
|
|
while(my $st=) { |
303
|
|
|
|
|
|
|
$st=~s/^\s+|\s+$|#.*$//gs; |
304
|
|
|
|
|
|
|
next if $st eq ""; |
305
|
|
|
|
|
|
|
my ($k,$v)=split(/=/,$st,2); |
306
|
|
|
|
|
|
|
$cfg{$k}=$v; |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
return %cfg; |
309
|
|
|
|
|
|
|
} |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# Обработка Multipart-данных формы |
312
|
|
|
|
|
|
|
# void _parseMultipart() |
313
|
|
|
|
|
|
|
our ($InBuf, $InLength); # our для strict |
314
|
|
|
|
|
|
|
sub _parseMultipart |
315
|
|
|
|
|
|
|
{ # Устанавливаем директорию и другие параметры для закачки (если разрешена) |
316
|
|
|
|
|
|
|
my %cfg=_readUplConf(); # свойства закачки |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
#------- Работа с STDIN с возможностью "запихивания" данных обратно в поток |
319
|
|
|
|
|
|
|
$InBuf=""; $InLength=$ENV{CONTENT_LENGTH}; |
320
|
|
|
|
|
|
|
sub _readInput { |
321
|
|
|
|
|
|
|
my $sz=shift||$InLength; |
322
|
|
|
|
|
|
|
my $need=$MULTICHUNK_SIZE>$sz? $sz : $MULTICHUNK_SIZE; |
323
|
|
|
|
|
|
|
my $nBuf=length($InBuf)<$need? length($InBuf) : $need; |
324
|
|
|
|
|
|
|
my $out=substr($InBuf,0,$nBuf); $InBuf=substr($InBuf,$nBuf); |
325
|
|
|
|
|
|
|
read(STDIN,$out,$need-$nBuf,$nBuf) if $need-$nBuf>0; |
326
|
|
|
|
|
|
|
$InLength-=length($out); |
327
|
|
|
|
|
|
|
return $out; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
sub _putBack |
330
|
|
|
|
|
|
|
{ my ($data)=@_; |
331
|
|
|
|
|
|
|
$InBuf=$data.$InBuf; |
332
|
|
|
|
|
|
|
$InLength+=length($data); |
333
|
|
|
|
|
|
|
} |
334
|
|
|
|
|
|
|
sub _isEof { return !$InLength; } |
335
|
|
|
|
|
|
|
#-------- Конец внутренних функций |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
binmode(STDIN); |
338
|
|
|
|
|
|
|
# Сначала читаем разделитель и финальные "\r\n" |
339
|
|
|
|
|
|
|
my ($bound,$CRLF) = _readInput()=~/(^[^\r\n]*)([\r\n]*)(.*)/s; # Выделяем разделитель БЕЗ \n |
340
|
|
|
|
|
|
|
_putBack($3); |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
# Теперь читаем записи, завершенные разделителем |
343
|
|
|
|
|
|
|
while((my $Data=_readInput()) ne "") { |
344
|
|
|
|
|
|
|
if(substr($Data,0,2) eq "--") { last; } # Проверяем, не конец ли это |
345
|
|
|
|
|
|
|
# Выделяем ВСЕ строки заголовка (до пустой строки). |
346
|
|
|
|
|
|
|
$Data=~/^[$CRLF]*(.*?)$CRLF$CRLF(.*)/s |
347
|
|
|
|
|
|
|
or do { push @Errors, "Malformed multipart header"; return }; |
348
|
|
|
|
|
|
|
_putBack($2); # Остаток запихиваем обратно |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
# Получаем заголовки записи в %Headers |
351
|
|
|
|
|
|
|
my @Lines=split(/$CRLF/,$1); # строки заголовка |
352
|
|
|
|
|
|
|
my %Headers=(); |
353
|
|
|
|
|
|
|
foreach my $st (@Lines) { |
354
|
|
|
|
|
|
|
my ($k,$v)=split(/: */,$st,2); |
355
|
|
|
|
|
|
|
$Headers{lc($k)}=$v; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
if(!%Headers) { push @Errors, "Malformed multipart POST (no header)"; return; } |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
# Выделяем имя тэга и имя файла (если задано) |
360
|
|
|
|
|
|
|
my ($name)=$Headers{'content-disposition'}=~/\bname="?([^\";]*)"?/; |
361
|
|
|
|
|
|
|
my ($filename) = $Headers{'content-disposition'}=~/\bfilename="?([^\";]*)"?/; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
# Если это не закачка, то читаем данные и продолжаем |
364
|
|
|
|
|
|
|
if(!defined $filename || $filename eq "") { |
365
|
|
|
|
|
|
|
my ($body,$i); |
366
|
|
|
|
|
|
|
$body = ""; |
367
|
|
|
|
|
|
|
for($body=""; ($i=index($body,$bound))<0 && !_isEof(); ) { |
368
|
|
|
|
|
|
|
$body.=_readInput(); |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
if($i<0) { push @Errors, "Malformed multipart POST (no boundary after body)"; return; } |
371
|
|
|
|
|
|
|
_putBack(substr($body,$i+length($bound))); # запихиваем остаток назад |
372
|
|
|
|
|
|
|
_processPar($name,substr($body,0,$i-length($CRLF)),"post"); |
373
|
|
|
|
|
|
|
next; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
# Иначе это закачка. Записываем временный файл. |
377
|
|
|
|
|
|
|
my $temp=defined $cfg{dir}? tempnam($cfg{dir}):tempnam(); |
378
|
|
|
|
|
|
|
local *F; open(F,">$temp") or die("Cannot open temporary file $temp"); binmode(F); |
379
|
|
|
|
|
|
|
my $written=0; # сколько байт в файле |
380
|
|
|
|
|
|
|
my $stopWrite=0; # нужно ли записывать, или пропускать |
381
|
|
|
|
|
|
|
while(1) { |
382
|
|
|
|
|
|
|
# Файл слишком велик или же закачка запрещена?.. |
383
|
|
|
|
|
|
|
$stopWrite ||= |
384
|
|
|
|
|
|
|
!%cfg && "File not found: $CANUPL_FILE" |
385
|
|
|
|
|
|
|
|| (defined $cfg{maxsize} && $written>$cfg{maxsize}) && "File exceeds limit of $cfg{maxsize} bytes"; |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
my $body1=_readInput(); |
388
|
|
|
|
|
|
|
my $body2=_readInput(128); # для проверки разделителя длиной <128 байт |
389
|
|
|
|
|
|
|
my $body=$body1.$body2; |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
# Нашли конец файла (разделитель)? |
392
|
|
|
|
|
|
|
if((my $i=index($body,$bound))>=0) { |
393
|
|
|
|
|
|
|
$written+=$i-length($CRLF); |
394
|
|
|
|
|
|
|
print F substr($body,0,$i-length($CRLF)) if !$stopWrite; |
395
|
|
|
|
|
|
|
_putBack(substr($body,$i+length($bound))); |
396
|
|
|
|
|
|
|
last; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
$written+=length($body1); |
399
|
|
|
|
|
|
|
print F $body1 if !$stopWrite; |
400
|
|
|
|
|
|
|
_putBack($body2); |
401
|
|
|
|
|
|
|
} |
402
|
|
|
|
|
|
|
close(F); |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# Формируем значение параметра. |
405
|
|
|
|
|
|
|
## BUGFIX 13.07.2002: |
406
|
|
|
|
|
|
|
## раньше имя вида f[] и f{} приводило к неправильному |
407
|
|
|
|
|
|
|
## созданию этого хэша, т.к. было насколько вызовов |
408
|
|
|
|
|
|
|
## _processPar с суффиксами {filename}, {file} и т.д. |
409
|
|
|
|
|
|
|
my %hash=(); |
410
|
|
|
|
|
|
|
$hash{filename}=$filename; |
411
|
|
|
|
|
|
|
# Файл слишком большой, либо upload запрещен?.. |
412
|
|
|
|
|
|
|
if($stopWrite) { |
413
|
|
|
|
|
|
|
unlink($temp); |
414
|
|
|
|
|
|
|
$hash{aborted}=$stopWrite; |
415
|
|
|
|
|
|
|
} else { |
416
|
|
|
|
|
|
|
# Иначе все в порядке |
417
|
|
|
|
|
|
|
$hash{headers}=\%Headers; |
418
|
|
|
|
|
|
|
$hash{file}=$temp; |
419
|
|
|
|
|
|
|
$hash{size}=-s $temp; |
420
|
|
|
|
|
|
|
$hash{type}=$Headers{'content-type'} if $Headers{'content-type'}; |
421
|
|
|
|
|
|
|
} |
422
|
|
|
|
|
|
|
# Добавляем параметр. |
423
|
|
|
|
|
|
|
_processPar($name,\%hash,"post"); |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
END_OF_FUNC |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
'_parseCookies' => <<'END_OF_FUNC', |
430
|
|
|
|
|
|
|
# Разбирает пришедшие cookies |
431
|
|
|
|
|
|
|
sub _parseCookies |
432
|
|
|
|
|
|
|
{ my @Pairs = split("; *",$ENV{HTTP_COOKIE} || $ENV{COOKIE} || ""); |
433
|
|
|
|
|
|
|
foreach (@Pairs) { |
434
|
|
|
|
|
|
|
my ($key,$value); |
435
|
|
|
|
|
|
|
if(/^([^=]+)=(.*)/) { $key = $1; $value = $2; } else { $key = $_; $value = ''; } |
436
|
|
|
|
|
|
|
$key=URLDecode($key); |
437
|
|
|
|
|
|
|
$value=URLDecode($value); |
438
|
|
|
|
|
|
|
my $v=Unserialize($value); |
439
|
|
|
|
|
|
|
$value=defined($v)?$v:$value; |
440
|
|
|
|
|
|
|
_processPar($key,$value,"cookie"); |
441
|
|
|
|
|
|
|
} |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
END_OF_FUNC |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
'ExpireCalc' => <<'END_OF_FUNC', |
447
|
|
|
|
|
|
|
# int ExpireCalc(string $tm) |
448
|
|
|
|
|
|
|
# This routine creates an expires time exactly some number of |
449
|
|
|
|
|
|
|
# hours from the current time. It incorporates modifications from Mark Fisher. |
450
|
|
|
|
|
|
|
# Format for time $tm can be in any of the forms... |
451
|
|
|
|
|
|
|
# "now" -- expire immediately |
452
|
|
|
|
|
|
|
# "+180s" -- in 180 seconds |
453
|
|
|
|
|
|
|
# "+2m" -- in 2 minutes |
454
|
|
|
|
|
|
|
# "+12h" -- in 12 hours |
455
|
|
|
|
|
|
|
# "+1d" -- in 1 day |
456
|
|
|
|
|
|
|
# "+3M" -- in 3 months |
457
|
|
|
|
|
|
|
# "+2y" -- in 2 years |
458
|
|
|
|
|
|
|
# "-3m" -- 3 minutes ago(!) |
459
|
|
|
|
|
|
|
sub ExpireCalc |
460
|
|
|
|
|
|
|
{ my($time)=@_; |
461
|
|
|
|
|
|
|
my(%mult)=('s'=>1, 'm'=>60, 'h'=>60*60, 'd'=>60*60*24, 'M'=>60*60*24*30, 'y'=>60*60*24*365); |
462
|
|
|
|
|
|
|
my($offset); |
463
|
|
|
|
|
|
|
if(lc($time) eq 'now') { $offset = 0; } |
464
|
|
|
|
|
|
|
elsif($time=~/^([+-](?:\d+|\d*\.\d*))([mhdMy]?)/) { $offset = ($mult{$2} || 1)*$1; } |
465
|
|
|
|
|
|
|
else { return $time; } |
466
|
|
|
|
|
|
|
return (time+$offset); |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
END_OF_FUNC |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
'Expires' => <<'END_OF_FUNC', |
472
|
|
|
|
|
|
|
# int Expires(int $time, string $format) |
473
|
|
|
|
|
|
|
# This internal routine creates date strings suitable for use in |
474
|
|
|
|
|
|
|
# cookies ($format="cookie") and HTTP headers ($format="http" or nothing). |
475
|
|
|
|
|
|
|
# (They differ, unfortunately.) Thanks to Fisher Mark for this. |
476
|
|
|
|
|
|
|
sub Expires |
477
|
|
|
|
|
|
|
{ my($time,$format) = @_; $format ||= 'http'; |
478
|
|
|
|
|
|
|
my(@MON)=qw/Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec/; |
479
|
|
|
|
|
|
|
my(@WDAY) = qw/Sun Mon Tue Wed Thu Fri Sat/; |
480
|
|
|
|
|
|
|
# pass through preformatted dates for the sake of expire_calc() |
481
|
|
|
|
|
|
|
$time = ExpireCalc($time); return $time unless $time =~ /^\d+$/; |
482
|
|
|
|
|
|
|
# cookies use '-' as date separator, HTTP uses ' ' |
483
|
|
|
|
|
|
|
my($sc) = ' '; $sc = '-' if $format eq "cookie"; |
484
|
|
|
|
|
|
|
my($sec,$min,$hour,$mday,$mon,$year,$wday) = gmtime($time); |
485
|
|
|
|
|
|
|
return sprintf("%s, %02d$sc%s$sc%04d %02d:%02d:%02d GMT", |
486
|
|
|
|
|
|
|
$WDAY[$wday],$mday,$MON[$mon],$year+1900,$hour,$min,$sec); |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
END_OF_FUNC |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
'SetCookie' => <<'END_OF_FUNC', |
492
|
|
|
|
|
|
|
# void SetCookie(string $name, string $value [,int $expire][,$path][,$domain][bool $secure]) |
493
|
|
|
|
|
|
|
# Устанавливает cookie с именем $name и значение $value ($value может быть сложным объектом |
494
|
|
|
|
|
|
|
# - в частности, ссылкой на массив или хэш). |
495
|
|
|
|
|
|
|
# Если $value не задан (undef), cookie удаляется. |
496
|
|
|
|
|
|
|
# Если $expire не задан, время жизни становится бесконечным. Если задан, но равен |
497
|
|
|
|
|
|
|
# нулю - создается one-session cookie. |
498
|
|
|
|
|
|
|
# Параметр $expire можно задавать в виде, который "понимает" функция ExpireCalc(). |
499
|
|
|
|
|
|
|
sub SetCookie |
500
|
|
|
|
|
|
|
{ my ($name,$value,$expires,$path,$domain,$secure)=@_; |
501
|
|
|
|
|
|
|
my $NeedDel=0; |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
# [12.03.2002] Можно и без этого. |
504
|
|
|
|
|
|
|
# if(!defined $path) { |
505
|
|
|
|
|
|
|
# $path=$ENV{SCRIPT_NAME}; |
506
|
|
|
|
|
|
|
# $path=~s{/[^/]*$}{}sg; |
507
|
|
|
|
|
|
|
# $path.="/"; |
508
|
|
|
|
|
|
|
# } |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
if(!defined $expires) { $expires="+20y"; } |
511
|
|
|
|
|
|
|
if(!defined $value) { $value=""; $expires="-3y"; $NeedDel=1; } |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
my @Param; |
514
|
|
|
|
|
|
|
push(@Param,URLEncode($name)."=".URLEncode(Serialize($value))); |
515
|
|
|
|
|
|
|
push(@Param,"domain=$domain") if defined $domain; |
516
|
|
|
|
|
|
|
push(@Param,"path=$path") if defined $path; |
517
|
|
|
|
|
|
|
push(@Param,"expires=".Expires($expires,"cookie")) if $expires; |
518
|
|
|
|
|
|
|
push(@Param,'secure') if $secure; |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
my $cook="Set-Cookie: ".join("; ",@Param); |
521
|
|
|
|
|
|
|
eval { |
522
|
|
|
|
|
|
|
local ($SIG{__WARN__},$SIG{__DIE__})=(sub {}, sub {}); |
523
|
|
|
|
|
|
|
require CGI::WebOut; |
524
|
|
|
|
|
|
|
}; |
525
|
|
|
|
|
|
|
if($@) { |
526
|
|
|
|
|
|
|
# Если не вышло загрузить CGI::WebOut, то просто печатаем. |
527
|
|
|
|
|
|
|
print $cook . "\r\n"; |
528
|
|
|
|
|
|
|
} else { |
529
|
|
|
|
|
|
|
CGI::WebOut::Header($cook); |
530
|
|
|
|
|
|
|
} |
531
|
|
|
|
|
|
|
if(!$NeedDel) { _processPar($name,$value,"cookie"); } |
532
|
|
|
|
|
|
|
else { _processPar($name,undef,"cookie"); } |
533
|
|
|
|
|
|
|
# Экспортируем Cookie во все нужные модули |
534
|
|
|
|
|
|
|
export_vars(); |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
END_OF_FUNC |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
'DropCookie' => <<'END_OF_FUNC', |
540
|
|
|
|
|
|
|
# void DropCookie(string $name [,$path] [,$domain]) |
541
|
|
|
|
|
|
|
# Удаляет cookie с именем $name. Параметры $path и $domain |
542
|
|
|
|
|
|
|
# должны точно совпадать с теми, которые были заданы при |
543
|
|
|
|
|
|
|
# установке Cookie. |
544
|
|
|
|
|
|
|
sub DropCookie |
545
|
|
|
|
|
|
|
{ my ($name,$path,$domain)=@_; |
546
|
|
|
|
|
|
|
SetCookie($name,undef,undef,$path,$domain); |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
END_OF_FUNC |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
'Serialize' => <<'END_OF_FUNC', |
552
|
|
|
|
|
|
|
# string Serialize(mixed @args) |
553
|
|
|
|
|
|
|
# Упаковывает в строку любой (практически) объект. Так что не обязательно передавать |
554
|
|
|
|
|
|
|
# этой функции ссылку - можно прямо объект целиком. |
555
|
|
|
|
|
|
|
# (В этом случае он будет рассмотрен как список). |
556
|
|
|
|
|
|
|
# Нельзя упаковывать объекты, содержащие ссылки на функции и дескрипторы файлов. |
557
|
|
|
|
|
|
|
# В случае ошибки возвращает undef и выводит warning. |
558
|
|
|
|
|
|
|
sub Serialize |
559
|
|
|
|
|
|
|
{ my $st="L".($#_+1).$Div2; |
560
|
|
|
|
|
|
|
foreach my $Arg (@_) { |
561
|
|
|
|
|
|
|
while((my $Ref=ref($Arg)) eq "REF") { $st.="r"; $Arg=$$Arg; } |
562
|
|
|
|
|
|
|
if(ref($Arg) ne "") { $st.="r"; } |
563
|
|
|
|
|
|
|
if(ref($Arg) eq "") { $st.=length($Arg).$Div1.$Arg; } |
564
|
|
|
|
|
|
|
elsif(ref($Arg) eq "SCALAR") { $st.=length($$Arg).$Div1.$$Arg; } |
565
|
|
|
|
|
|
|
elsif(ref($Arg) eq "ARRAY") { $st.=Serialize(@$Arg); } |
566
|
|
|
|
|
|
|
elsif(ref($Arg) eq "HASH") { $st.="H".Serialize(%$Arg); } |
567
|
|
|
|
|
|
|
else { warn("Serialize: invalid field type '".ref($Arg)."'"); return undef; } |
568
|
|
|
|
|
|
|
} |
569
|
|
|
|
|
|
|
return $st; |
570
|
|
|
|
|
|
|
} |
571
|
|
|
|
|
|
|
END_OF_FUNC |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
'Unserialize' => <<'END_OF_FUNC', |
575
|
|
|
|
|
|
|
# mixed _Unserialize(string $st) |
576
|
|
|
|
|
|
|
# Internal function. |
577
|
|
|
|
|
|
|
sub _Unserialize |
578
|
|
|
|
|
|
|
{ my ($st,$TotalLen)=@_; |
579
|
|
|
|
|
|
|
# Считаем число ссылок |
580
|
|
|
|
|
|
|
my $RefCount; |
581
|
|
|
|
|
|
|
for($RefCount=0; substr($st,$RefCount,1) eq "r"; $RefCount++) {;} |
582
|
|
|
|
|
|
|
$$TotalLen+=$RefCount; $st=substr($st,$RefCount); |
583
|
|
|
|
|
|
|
# Определяем тип |
584
|
|
|
|
|
|
|
my $Type="S"; # Может быть еще: "HL" (да, 2 символа!!!) или "L" |
585
|
|
|
|
|
|
|
if(substr($st,0,1) eq "H") { $Type="H"; $st=substr($st,2); $$TotalLen+=2; } |
586
|
|
|
|
|
|
|
elsif(substr($st,0,1) eq "L") { $Type="L"; $$TotalLen++; $st=substr($st,1); } |
587
|
|
|
|
|
|
|
# Выполняем действия в зваисимости от типа |
588
|
|
|
|
|
|
|
my $PResult; |
589
|
|
|
|
|
|
|
if($Type eq "S") { |
590
|
|
|
|
|
|
|
# Это - обычная строка. |
591
|
|
|
|
|
|
|
my $len=substr($st,0,my $p=index($st,$Div1)); # 0123.aaabbb |
592
|
|
|
|
|
|
|
$st=substr($st,$p+1); $$TotalLen+=$p+1+$len; # ^ ^p |
593
|
|
|
|
|
|
|
# Распаковываем исходную строку |
594
|
|
|
|
|
|
|
my $s=substr($st,0,$len); $PResult=\$s; |
595
|
|
|
|
|
|
|
} elsif($Type eq "L" || $Type eq "H") { |
596
|
|
|
|
|
|
|
my @Unpack; |
597
|
|
|
|
|
|
|
my $size=substr($st,0,my $p=index($st,$Div2)); |
598
|
|
|
|
|
|
|
$st=substr($st,$p+1); $$TotalLen+=$p+1; |
599
|
|
|
|
|
|
|
foreach my $i (0..$size-1) { |
600
|
|
|
|
|
|
|
my $len; push(@Unpack,_Unserialize($st,\$len)); |
601
|
|
|
|
|
|
|
$$TotalLen+=$len; |
602
|
|
|
|
|
|
|
$st=substr($st,$len); |
603
|
|
|
|
|
|
|
} |
604
|
|
|
|
|
|
|
if($Type eq "L") { $PResult=\@Unpack; } else { my %Hash=@Unpack; $PResult=\%Hash; } |
605
|
|
|
|
|
|
|
} |
606
|
|
|
|
|
|
|
# We have the pointer to the object $PResult. Returning the (n-1)-th reference on it. |
607
|
|
|
|
|
|
|
for(my $i=0; $i<$RefCount; $i++) { my $tmp=$PResult; $PResult=\$tmp; } |
608
|
|
|
|
|
|
|
if(ref($PResult) eq "ARRAY") { return wantarray?@$PResult:@$PResult[0]; } |
609
|
|
|
|
|
|
|
elsif(ref($PResult) eq "HASH") { return %$PResult; } |
610
|
|
|
|
|
|
|
else { return $$PResult; } |
611
|
|
|
|
|
|
|
} |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
# mixed _Unserialize(string $st) |
615
|
|
|
|
|
|
|
# Распаковывает строку, созданную ранее при помощи Serialize(). Возвращает то, что |
616
|
|
|
|
|
|
|
# было когда-то передано в параметрах Serialize. |
617
|
|
|
|
|
|
|
# В случае ошибки возвращает undef и выдает warning. |
618
|
|
|
|
|
|
|
sub Unserialize |
619
|
|
|
|
|
|
|
{ return undef if !defined $_[0]; |
620
|
|
|
|
|
|
|
my @Result=(); my $err=0; |
621
|
|
|
|
|
|
|
local $SIG{__WARN__}=sub { $err=1; }; |
622
|
|
|
|
|
|
|
local $SIG{__DIE__}=sub { $err=1; }; |
623
|
|
|
|
|
|
|
eval { @Result=_Unserialize($_[0]); }; |
624
|
|
|
|
|
|
|
if($err||$@) { return undef; } |
625
|
|
|
|
|
|
|
return wantarray?@Result:$Result[0]; |
626
|
|
|
|
|
|
|
} |
627
|
|
|
|
|
|
|
END_OF_FUNC |
628
|
|
|
|
|
|
|
); |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
#eval join("", values %CODE); |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
our $AUTOLOAD; |
633
|
|
|
|
|
|
|
sub AUTOLOAD { |
634
|
0
|
0
|
|
0
|
|
|
my ($pkg, $sub) = $AUTOLOAD =~ /^(.*)::(.*)$/s or return; |
635
|
0
|
0
|
|
|
|
|
return if $pkg ne __PACKAGE__; |
636
|
0
|
|
0
|
|
|
|
eval($CODE{$sub} or return); |
637
|
0
|
|
|
|
|
|
goto &$sub; |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
_reparseAll(); |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
return 1; |
643
|
|
|
|
|
|
|
__END__ |