Aion-Format

 view release on metacpan or  search on metacpan

lib/Aion/Format/Url.pm  view on Meta::CPAN

		&& *{$Aion::Format::Url::{$_}}{CODE} && !/^(_|(NaN|import)\z)/n
} keys %Aion::Format::Url::;


#@category escape url

use constant UNSAFE_RFC3986 => qr/[^A-Za-z0-9\-\._~]/;

# Эскейпит значение
sub to_url_param(;$) {
	my ($param) = @_ == 0? $_: @_;
	use bytes;
	$param =~ s/${\ UNSAFE_RFC3986}/$& eq " "? "+": sprintf "%%%02X", ord $&/ge;
	$param
}

# Преобразует в формат url-параметров
sub to_url_params(;$) {
	my ($param) = @_ == 0? $_: @_;

	my @R;
	my @S = [$param];
	while(@S) {
		my $u = pop @S;
		my ($x, $key) = @$u;
		
		if(ref $x eq "HASH") {
			push @S, defined($key)
				? (map [$x->{$_}, "$key\[${\to_url_param}]"], sort keys %$x)
				: (map [$x->{$_}, to_url_param], sort keys %$x)
			;
		}
		elsif(ref $x eq "ARRAY") {
			my $i = '';
			push @S, map [$_, "$key\[${\($i++)}]"], @$x;
		}
		elsif(!defined $x) {}
		elsif($x eq 1) { unshift @R, $key }
		else {
			unshift @R, join "=", $key, to_url_param $x;
		}
	}
	
	join "&", @R
}

# Определяет кодировку. В koi8-r и в cp1251 большие и малые буквы как бы поменялись местами, поэтому у правильной кодировки вес будет больше
sub _bohemy {
	my ($s) = @_;
	my $c = 0;
	while($s =~ /[а-яё]+/gi) {
		my $x = $&;
		if($x =~ /^[А-ЯЁа-яё][а-яё]*$/) { $c += length $x } else { $c -= length $x }
	}
	$c
}

sub from_url_param(;$) {
	my ($param) = @_ == 0? $_: @_;

	utf8::encode($param) if utf8::is_utf8($param);

	{
		no utf8;
		use bytes;
		$param =~ tr!\+! !;
		$param =~ s!%([\da-f]{2})! chr hex $1 !iage;
	}

	eval { $param = Encode::decode_utf8($param, Encode::FB_CROAK) };

	if($@) { # видимо тут кодировка cp1251 или koi8-r
		my $cp  = Encode::decode('cp1251', $param);
		my $koi = Encode::decode('koi8-r', $param);
		# выбираем перекодировку в которой меньше больших букв внутри слова
		$param = _bohemy($koi) > _bohemy($cp)? $koi: $cp;
	}

	$param
}

sub _set_url_param(@) {
	my ($x, $val) = @_;
	if(ref $$x eq "ARRAY") { push @$$x, $val }
	elsif(ref $$x eq "HASH") { $$x = [$$x, $val] }
	else { $$x = $val }
}

sub from_url_params(;$) {
	my ($params) = @_ == 0? $_: @_;

	my %param;
	my $x;
	my $was_val;

	while($params =~ /\G (?: 
		(?:^|&) (?<key1> [^&=\[\]]* )
		| \[ (?<key> [^\[\]]* ) \]
		| (?: = (?<val> [^&]*) )
		| .
	) /gsx) {

		if(exists $+{key1}) {
			_set_url_param $x, 1 unless $was_val;
			$was_val = 0;
			$x = \$param{from_url_param $+{key1}};
		}
		elsif(exists $+{key}) {
			# Добрасываем в массив
			if($+{key} eq '' || int $+{key} eq $+{key}) {
				$$x = [$$x] if ref $$x ne 'ARRAY' && defined $$x;
				$x = \$$x->[$+{key}];
			}
			else {
				# Добавляем в хеш
				my $key = from_url_param $+{key};
				$$x = {$key => $$x} if ref $$x ne 'HASH' && defined $$x;
				$x = \$$x->{$key};
			}
		}
		elsif(exists $+{val}) {
			_set_url_param $x, from_url_param $+{val};
			$was_val = 1;
		}
		
	}
	
	_set_url_param $x, 1 unless $was_val;

	\%param



( run in 1.694 second using v1.01-cache-2.11-cpan-39bf76dae61 )