суббота, 2 апреля 2011 г.

PHP-разработчики - люди которых я боюсь

Сегодня на Хабре наткнулся на неплохую задачу для своих мозгов.

Нужно было реализовать функцию read_conf принимающую имя файла с содержимым:

id=www
session.timeout=120
session.server.0.host=127.0.0.1
session.server.0.port=1111
session.server.0.id=session1
session.server.1.host=127.0.0.1
session.server.1.port=1111
session.server.1.id=session2
image.width=640
image.height=480
image.watermark.small=wsmall.png
image.watermark.normal=wnormal.png


Которая приводит конфиг к такой переменной:

array(3) {
    ["id"]=>strong(3) "www"
    ["session"]=>array(2) {
        ["timeout"]=>string(3) "120"
        ["server"]=>array(2) {
            [0]=>
            array(3) {
                ["host"]=>
                string(9) "127.0.0.1"
                ["post"]=>
                string(4) "1111"
                ["id"]=>
                string(8) "session1"
            }
            [1]=>
            array(3) {
                ["host"]=>
                string(9) "127.0.0.1"
                ["port"]=>
                string(4) "1111"
                ["id"]=>
                string(8) "session2"
            }
        }
    }
    ["image"]=>
    array(3) {
        ["width"]=>
        string(3) "640"
        ["height"]=>
        string(3) "480"
        ["watermark"]=>
        array(2) {
            ["small"]=>
            string(10) "wsmall.png"
            ["normal"]=>
            string(11) "wnormal.png"
        }
    }
}



На задачу выделялось 10 минут.

Задача не очень сложная, если не ограничиваться временем, честно признаться мне немного не хватило 10 минут,
но я и не претендую на звания "Гуру php", да и не это важно.

Я как человек любопытный стал просматривать комментарии, чтобы найти наиболее интересные решения данной задачи.

По мнению большинства читателей топика наилучшее решение (наибольшее число позитивных отзывов за комментарий)
было следующее решение:

<?php

$r = read_conf( "config.txt" );
print var_dump( $r );

function read_conf($filename) {
    foreach (parse_ini_file($filename) as $key=>$value) {
        $key = vsprintf('$result["%s"] = "%s";', array(
            str_replace('.', '"]["', $key),
            $value,
        ));
        eval($key);
    }
    return $result;
}

?>


Гениально! Наименьшее число строк! Никакой рекурсии! Умница!

Вы тоже так подумали? Нет? И ПРАВИЛЬНО!

Ведь дырка! Ну как никто из них об этом не подумал? Теперь в конфиг можно вставить, какой угодно код, который будет выполнен запускаемым скриптом!

Не верите? Попробуйте вот такой конфиг (будет работать в Unix-подобной ОС, но для пользователей Windows можно написать свой пример).

id=www
session.timeout=120
session.server.0.host=127.0.0.1
session.server.0.port=1111
session.server.0.id=session1
session.server.1.host=127.0.0.1
session.server.1.port=1111
session.server.1.id=session2
image.width=640"\";shell_exec('ls -l > hack');\""
image.height=480
image.watermark.small=wsmall.png
image.watermark.normal=wnormal.png



Я его немного изменил, добавил вот такой кусочек "\";shell_exec('ls -l > hack');\"". И теперь имею снимок поточной директории.
Но мы можем с легкостью изменить конфиг добавив вместо 'ls -l > hack', например 'rm -Rf /'. В общем еще очень много гадости можно придумать.

Но самое главное об этом НИКТО не подумал. Такой серьезный информационный портал. Множество действительно профессиональных php-программистов. И НИКТО не сделал по этому поводу замечания. А теперь представьте, масштаб трагедии...

Как таким людям можно доверить серьезный проект? В общем я бы побоялся.

А Вы?

С ув. antonfin

P.S. Нет, все таки нашелся человек, который сделал замечания по данному вопросу. Но его комментарий не был поддержан, я бы даже сказал, что он был обвинен в ханжестве.

3 комментария:

  1. Вот код на Perl, без рекурсии. Было бы больше времени, то можно было бы сделать красивше :)

    sub read_conf {
    my $file = shift;
    my $conf = {};
    open(my $fh, '<', $file) or die "ERROR: $!";

    while ( my $line = <$fh> ) {
    chomp($line);
    my ($key, $val) = split(/=/, $line);
    my @sub_keys = split(/\./, $key);

    my ($parent, $i) = ( $conf, 0 );
    for ( $i = 0; $i<$#sub_keys; $i++ ){
    $parent = $parent->{$sub_keys[$i]} ||= {};
    }
    $parent->{$sub_keys[$i]} = $val;
    }

    close $fh;
    return $conf;
    }

    ОтветитьУдалить
  2. И как вы этой дыркой сможете воспользоваться на реальном сайте?

    ОтветитьУдалить