Вход

Просмотр полной версии : PHP-вопрос



CoValent
19.03.2010, 16:06
В сайте использован вызов содержимого по линку типа "index.php?id=2":

<?php
if ($id=="") {
include ("1.htm");
} else {
include ("$id.htm");
}
?>
Однако, по любому линку вызывается лишь содержимое "1.htm" - но не "2.htm", как в примере вызова наверху.

Подскажите, пожалуйста, где собака порылась? А то мозги уже перегрелись...

Спасибо!

ilya_rad
19.03.2010, 16:07
надо так писать:
include ($id.".htm");

CoValent
19.03.2010, 16:12
Увы, Илья, не работает.

ilya_rad
19.03.2010, 16:19
щас.. минутку..
Проверю сам :)

CoValent
19.03.2010, 16:22
Уточнение: кручу локально в денвере. Хотя, думаю, не в этом дело...

Кстати, точка, выделенная красным ($id.".htm") - точно нужна?

ilya_rad
19.03.2010, 16:27
if (!@$id)
{include ("1.htm");
}
else
{include ("$id".".htm");
}



вот так у меня заработало

CoValent
19.03.2010, 16:37
Увы, у меня содержимое "2.htm" так и не вызывается... :(

ilya_rad
19.03.2010, 16:43
ну вот я залил на хост, работает:
http://berossi.by/i.php

там лежит три файла 1.htm, 2.htm, 3.htm

CoValent
19.03.2010, 16:51
ну вот я залил на хост, работает:
http://berossi.by/i.php

там лежит три файла 1.htm, 2.htm, 3.htm
Можешь их в аттач сюда засунуть?

Mirnyi
19.03.2010, 16:53
Увы, у меня содержимое "2.htm" так и не вызывается... :(
Посмотреть настройки PHP, попробовать через $_GET

<?php
if ($_GET['id']=="") {
include ("1.htm");
} else {
include ("$_GET['id']".".htm");
}
?>

ilya_rad
19.03.2010, 16:54
Да, засовываю все файлы

ilya_rad
19.03.2010, 16:56
А, да, php.ini посмотри на предмет
register_globals = On

CoValent
19.03.2010, 16:57
Посмотреть настройки PHP, попробовать через $_GET
Андрей... я в этом дуб дубом. Можешь пошагово?

CoValent
19.03.2010, 16:58
У меня локально не срабатывает. :(

А, да, php.ini посмотри на предмет
register_globals = On
Пошёл искать...

ilya_rad
19.03.2010, 17:01
если лень искать, то можно через GET.
дописать самой первой строкой $id=$_GET["id"];

CoValent
19.03.2010, 17:01
Ура, заработало! Спасибо, Илья: нашёл в php.ini строчку и исправил! :cool:

Mirnyi
19.03.2010, 17:02
Посмотреть настройки PHP, попробовать через $_GET

<?php
if ($_GET['id']=="") {
include ("1.htm");
} else {
include ("$_GET['id']".".htm");
}
?>
Вот так
а разрешать регистрировать глобалы уже считается моветоном, хотя многие старые скрипты без этого не работают

CoValent
19.03.2010, 17:06
Вот так
а разрешать регистрировать глобалы уже считается моветоном, хотя многие старые скрипты без этого не работают
А вот этот вариант не работает, ругается на строчку

include ("$_GET['id']".".htm");
через

Parse error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE, expecting T_STRING or T_VARIABLE or T_NUM_STRING in Z:\home\mysite\www\index.php on line 7
Потому что глобальную исправили?

ilya_rad
19.03.2010, 17:07
Вот так
а разрешать регистрировать глобалы уже считается моветоном, хотя многие старые скрипты без этого не работают


Ну, на всех хостах, с которыми я работал, разрешены глобалы.
Хотя с точки зрения безопасности их лучше запретить :)

Mirnyi
19.03.2010, 17:10
А вот этот вариант не работает, ругается на строчку

include ("$_GET['id']".".htm");
через

Потому что глобальную исправили?
Нет. Тут действительно где-то в синтаксисе косяк
Что-то с кавычками.
Попробуй так

include ($_GET['id'].".htm");

ilya_rad
19.03.2010, 17:11
А вот этот вариант не работает, ругается на строчку

include ("$_GET['id']".".htm");
через

Потому что глобальную исправили?
Нет, то, что глобалы разрешены - на работу $_GET отражаться не должно.
Скорее всего, ошибка происходит, когда вызываешь файл без параметра id, типа http://localhost/index.php
А http://localhost/index.php (http://localhost/index.php)?id=1 должно работать нормально

CoValent
19.03.2010, 17:20
...Попробуй так...
О, это решение заработало! Спасибо, Андрей!

Mirnyi
19.03.2010, 17:22
О, это решение заработало! Спасибо, Андрей!
А ещё лучше


<?php
if (isset($_GET['id'])) {
include ($_GET['id'].".htm");
} else {
include ("1.htm");
}
?>

CoValent
19.03.2010, 17:26
А ещё лучше...
Спасибо, Андрей: тоже работает! :cool:

P.S. Блин, как грустно быть ламером в этом лучшем из миров - как работает эта конструкция я уже не понимаю... :(

Mirnyi
19.03.2010, 17:32
Спасибо, Андрей: тоже работает! :cool:

P.S. Блин, как грустно быть ламером в этом лучшем из миров - как работает эта конструкция я уже не понимаю... :(
isset($_GET('id')) выдаёт истину, если в запросе есть id=чему-то там.
А вообще, с точки зрения безопасности
include с непроверенной переменной из запроса - жуткая дыра.
Через id можно заинклюдить что хочешь.

Количество допустимых id должно быть ограничено и через if проверять и направлять на конкретную страницу

<?php
if (!isset($_GET['id'])) {
include ("1.htm");
} else {
if($_GET['id']=1){
include("1.htm");
}
if($_GET['id']=2){
include("2.htm");
}
........
}
?>

Или хотябы проверять, что $_GET['id'] цифра, а не что-нибудь вроде "http://lomaster.com/crack"
Некрасиво, длинно, но смысл есть.

DogEater
19.03.2010, 17:54
А можно я тоже кааапельку повыпендриваюсь?

if (isset ($_GET['id']) and preg_match ("/^\d$/",$_GET['id'])){
include($_GET['id'].".htm");
}
else {
include("1.htm");
}

Mirnyi
19.03.2010, 18:01
А можно я тоже кааапельку повыпендриваюсь?

if (isset ($_GET['id']) and preg_match ("/^\d$/",$_GET['id'])){
include($_GET['id'].".htm");
}
else {
include("1.htm");
}:cool:
Я-то по-ламерски. Регулярники для меня - тёмный лес :ups:
Значение набора символов /^\d$/ у меня в голове не помещается :D

DogEater
19.03.2010, 19:04
:cool:
Я-то по-ламерски. Регулярники для меня - тёмный лес :ups:
Значение набора символов /^\d$/ у меня в голове не помещается :D
Сразу после начала строки идёт одна цифра, далее следует конец строки.
Это гарантированная проверка на то, что в переменной только один символ и это есть цифра. После чего уже можно спокойно инклюдить.

Mirnyi
19.03.2010, 19:10
Это гарантированная проверка на то, что в переменной только один символ и это есть цифра.
:eek:
отвалбашки:ok:
:D

harinalex
19.03.2010, 19:20
Сразу после начала строки идёт одна цифра, далее следует конец строки.
Это гарантированная проверка на то, что в переменной только один символ и это есть цифра. После чего уже можно спокойно инклюдить.

тогда уж надо предусмотреть и 99.htm (вряд ли там так мало файлов ) . имхо , лучше просто /[0-9]/ или /^[\d]+/

DogEater
19.03.2010, 19:24
:eek:
отвалбашки:ok:
:D

отвал говоришь?
А если нужны цифры только от 3 до 5 и во входящих данных - мусор?


if (preg_match ("/^[\D]*/([3-5]{1}).*$/",$_GET['id'],$id) ){
include($id[1].".htm");
}
else {
include("1.htm");
}


---------- Добавлено в 19:24 ---------- Предыдущее сообщение было написано в 19:21 ----------


тогда уж надо предусмотреть и 99.htm (вряд ли там так мало файлов ) . имхо , лучше просто /[0-9]/
скорее всего 0.htm вряд ли стоит учитывать.

if (preg_match ("/^[\D]*/([1-9][0-9]?).*$/",$_GET['id'],$id) ){
include($id[1].".htm");
}
else {
include("1.htm");
}

Mirnyi
19.03.2010, 19:26
тогда уж надо предусмотреть и 99.htm (вряд ли там так мало файлов ) . имхо , лучше просто /[0-9]/
И тогда функция вернёт истину на любой набор символов хоть с одной цифрой (если я не ошибаюсь)
Вот за то и не люблю регулярные, что можно написать такого, что сам потом не разберёшь.
Но, конечно, это только отмазка, чтобы мозг не ломать "китайской грамотой".
Если знать их хорошо и функции которые с ними работают, то инструмент мощнейший.

harinalex
19.03.2010, 19:29
И тогда функция вернёт истину на любой набор символов хоть с одной цифрой (если я не ошибаюсь)
Вот за то и не люблю регулярные, что можно написать такого, что сам потом не разберёшь.
Но, конечно, это только отмазка, чтобы мозг не ломать "китайской грамотой".
Если знать их хорошо и функции которые с ними работают, то инструмент мощнейший.

нет , только этот диапазон цифр

DogEater
19.03.2010, 19:29
И тогда функция вернёт истину на любой набор символов хоть с одной цифрой (если я не ошибаюсь)
Вот за то и не люблю регулярные, что можно написать такого, что сам потом не разберёшь.
Но, конечно, это только отмазка, чтобы мозг не ломать "китайской грамотой".
Если знать их хорошо и функции которые с ними работают, то инструмент мощнейший.

Не пожидись, купи себе немножечко Джеффри Фридла, "Регулярные выражения". Я купил второе издание в 2003 за 256 рублей, и до сих пор не жалею.
Даже если ты осилишь первые 3 главы - это сильно поднимет твой уровень.

Mirnyi
19.03.2010, 19:31
отвал говоришь?
А если нужны цифры только от 3 до 5 и во входящих данных - мусор?

Да нет, я же не против :)
Даже наоборот - за. :cool:

harinalex
19.03.2010, 19:34
скорее всего 0.htm вряд ли стоит учитывать.

if (preg_match ("/^[\D]*/([1-9][0-9]?).*$/",$_GET['id'],$id) ){
include($id[1].".htm");
}
else {
include("1.htm");
}

в 0.htm можно какую-нибудь обидную фразу написАть :)

главное , что инъекцию не даст сделать - и ладно .

Mirnyi
19.03.2010, 19:38
нет , только этот диапазон цифр


int preg_match (string pattern, string subject [, array matches [, int flags]])

Ищет в subject совпадения с регулярным выражением, заданным в pattern.

Если matches предоставлен, он заполняется результатами поиска. $matches[0] будет содержать текст, совпавший со всем патэрном, $matches[1] будет содержать текст, совпавший первым захваченным субпатэрном в скобках, и так далее.
Или я ничего не понимаю, или встретив одну цифру в subject, эта функция вернёт не 0, т.е. истину.
Т.е., можно и такую маску задать, но тогда нужно менять условия или инклюдить уже не переменную, а результаты функции (которые ещё выбрать нужно правильно).
Т.е., кроме самого регулярника нужно ещё учитывать что же оно реально делает в функции.

harinalex
19.03.2010, 20:02
Или я ничего не понимаю, или встретив одну цифру в subject, эта функция вернёт не 0, т.е. истину.
Т.е., можно и такую маску задать, но тогда нужно менять условия или инклюдить уже не переменную, а результаты функции (которые ещё выбрать нужно правильно).
Т.е., кроме самого регулярника нужно ещё учитывать что же оно реально делает в функции.

мне функция preg_match не нравится , имхо для таких целей лучше preg_match_all использовать , она не остановится после первого нахождения.
мне больше по душе htmlspecialchars(preg_replace("/[^1-9]/"),"",$id)


В общем , надо память освежить - пошел читать http://php.net/
;)

DogEater
19.03.2010, 20:08
Или я ничего не понимаю, или встретив одну цифру в subject, эта функция вернёт не 0, т.е. истину.
Т.е., можно и такую маску задать, но тогда нужно менять условия или инклюдить уже не переменную, а результаты функции (которые ещё выбрать нужно правильно).
Т.е., кроме самого регулярника нужно ещё учитывать что же оно реально делает в функции.
Отнесу к последнему выражению.
идёт начало строки, затем мусор (любое количество не-цифр), если затем встречается цифра от 1 до 9 то хорошо, а если после неё будет цифра от 0 до 9 -0 то ещё лучше(не будет второй цифры - фиг с ней, она не обязательна) - запомним эти цифры (потому что в скобках), а всё остальное - остаток строки до конца совпадёт с сочетанием .*(любое количество любых символов), но мы запомним первые попавшиеся цифры, и возьмём их из $id[1] (потому что в $id[0] будет всё что совпало с шаблоном, а в $id[1] - только то, что совпало в первых скобках)
таким образом мы вытащим из строки с мусором число от 1 до 99.

Mirnyi
19.03.2010, 20:31
Отнесу к последнему выражению.
идёт начало строки, затем мусор (любое количество не-цифр), если затем встречается цифра от 1 до 9 то хорошо, а если после неё будет цифра от 0 до 9 -0 то ещё лучше(не будет второй цифры - фиг с ней, она не обязательна) - запомним эти цифры (потому что в скобках), а всё остальное - остаток строки до конца совпадёт с сочетанием .*(любое количество любых символов), но мы запомним первые попавшиеся цифры, и возьмём их из $id[1] (потому что в $id[0] будет всё что совпало с шаблоном, а в $id[1] - только то, что совпало в первых скобках)
таким образом мы вытащим из строки с мусором число от 1 до 99.
Всё правильно, но, согласись, что это всёже не /[0-9]/, подставленное в первый пример.
А ошибки при использовании регулярных выражений вылазят довольно часто даже у профессионалов.
Я только говорю о том, что когда определён конечный словарь того, что может быть в запросе, часто проще и надёжнее запрос проверить в лоб.
Всё, что в $_GET генерируется самим кодом. Если это не бескончная случайная последовательность символов (не может быть любым), то всё что содержит мусор или проще говоря не совпадает с ограниченным числом возможных значений можно просто послать нафиг.
Это и в парсерах логов порой лучше работает, чем регулярное выражение в 14 этажей.

Кстати, спасибо за наводку на книжку - уже читаю.:cool:

DogEater
19.03.2010, 20:47
Всё правильно, но, согласись, что это всёже не /[0-9]/, подставленное в первый пример.
А ошибки при использовании регулярных выражений вылазят довольно часто даже у профессионалов.
Я только говорю о том, что когда определён конечный словарь того, что может быть в запросе, часто проще и надёжнее запрос проверить в лоб.
Всё, что в $_GET генерируется самим кодом. Если это не бескончная случайная последовательность символов (не может быть любым), то всё что содержит мусор или проще говоря не совпадает с ограниченным числом возможных значений можно просто послать нафиг.
Это и в парсерах логов порой лучше работает, чем регулярное выражение в 14 этажей.

У нас простейший пример - 2 цифры. В конце концов вполне сойдёт (\d\d?)
Поскольку я - сисадмин, значит профессиональный параноик. Поэтому входной контроль данных - не считаю лишним. Мало ли кто чего пошлёт. Код или не код сгенерировал запрос - я то откуда знаю?
вот - пример - проверка на похожесть ldap rdn с одновременным разбиенем на массив:

preg_match_all ("/([^=,]+=[^=,]+),?/",$person,$target)

а уж про парсинг пчелайновских счетов я вообще молчу(номера, длительность, цена) ;)


Кстати, спасибо за наводку на книжку - уже читаю.:cool:
Джеффри обещал, что книга будет читаться как роман. Не соврал.

Mirnyi
19.03.2010, 21:54
А можно ещё и вот так:
/^\d+$/ - любое целое число без лишних символов (включая 0)
или
/^[0-9]+$/ -тоже самое

:bravo::bravo:

Я теперь тоже по-китайски умею :D

CoValent
19.03.2010, 23:15
Так, краткое описание моей задачи и вывод:

1. Есть статическая оболочка сайта-визитки, подгружаемая через 3 вызова include (грубо - "статически шапка", "статически подвал" и "динамически контент").
2. Контент в HTML, причём имя файла значимое, а не цифровое.
3. Исходя из вышеперечисленных условий, а также возможности инъекции черехз вызов "чего попало" любые решения этой задачи, как цифровые, так и списковые, к сожалению, абсолютно неинтересны.

Ибо проще создать кучу контента с двумя статическими вызовами оболочки.

Большое спасибо всем, кто потратил своё время и просветил о нежелательности использования динамического вызова!

Mirnyi
19.03.2010, 23:27
Так, краткое описание моей задачи и вывод:

1. Есть статическая оболочка сайта-визитки, подгружаемая через 3 вызова include (грубо - "статически шапка", "статически подвал" и "динамически контент").
2. Контент в HTML, причём имя файла значимое, а не цифровое.
3. Исходя из вышеперечисленных условий, а также возможности инъекции черехз вызов "чего попало" любые решения этой задачи, как цифровые, так и списковые, к сожалению, абсолютно неинтересны.

Ибо проще создать кучу контента с двумя статическими вызовами оболочки.

Большое спасибо всем, кто потратил своё время и просветил о нежелательности использования динамического вызова!
А зря ты так.
Если есть куча файлов, лежащих известно где, то просто организуешь проверку папки с файлами на наличие файла с именем, поступившим через запрос. Если файл найден - выводишь, если нет - посылаешь нафиг.
Список-то у тебя уже есть.

CoValent
19.03.2010, 23:37
А зря ты так.
Если есть куча файлов, лежащих известно где, то просто организуешь проверку папки с файлами на наличие файла с именем, поступившим через запрос. Если файл найден - выводишь, если нет - посылаешь нафиг.
Список-то у тебя уже есть.
Почему зря и откуда у меня список?...

Сегодня содержание такое-то - а завтра хозяин попросил добавить пару html-файлов и двести фото...

Нет, конечно, если ты всерьёз считаешь, что мне проще сделать длинный список, чем вызывать поимённо нужный файл - то я с тобой соглашусь... но чем это будет проще я пока не понимаю.

Mirnyi
19.03.2010, 23:42
Почему зря и откуда у меня список?...

Сегодня содержание такое-то - а завтра хозяин попросил добавить пару html-файлов и двести фото...

Нет, конечно, если ты всерьёз считаешь, что мне проще сделать длинный список, чем вызывать поимённо нужный файл - то я с тобой соглашусь... но чем это будет проще я пока не понимаю.
Список у тебя на винте есть всегда.
Можно входящую строку проверить на слеши и сделать if fileexist()
А можно сделать list папки и сравнить поэлементно массив с входной строкой.
И так, и так никакая инъекция не пройдёт.

DogEater
19.03.2010, 23:56
Список у тебя на винте есть всегда.
Можно входящую строку проверить на слеши и сделать if fileexist()
А можно сделать list папки и сравнить поэлементно массив с входной строкой.
И так, и так никакая инъекция не пройдёт.

Ну да. Цифры в полученной переменной могут быть всего лишь номером(ключом) массива из имён файлов(см glob()). Сначала отдаёшь номер элемента массива, содержащего имя файла в ссылку, а при запросе по номеру подгружаешь контент по имени из этого элемента.
Куда уж безопаснее. :)
Вот так делаем ссылку:


<?php
$files=glob ($config['incpath']."/files/*jp*");
foreach ($files as $file){
print "<a href=".$SERVER['SCRIPT_NAME']."?id=".$id++.">Файл No $id</a>\n";
}
?>

Вот так формируем ответ:
Напрямую снаружи ничего не берётся. Только подкидывай фалы в папку(если *nix - регистр в имени файла учитывается).


<?php
$files=glob ($config['incpath']."/files/*jp*");
if (preg_match ("/(\d+)/",$_GET['id'],$id)){
if (is_file($files[$id[1]]))
include($files[$id[1]].".htm");
}
else {
if (is_file("1.htm"))
include("1.htm");
}
?>

Mirnyi
20.03.2010, 00:07
Ну да. Цифры в полученной переменной могут быть всего лишь номером(ключом) массива из имён файлов(см glob()). Сначала отдаёшь номер элемента массива, содержащего имя файла в ссылку, а при запросе по номеру подгружаешь контент по имени из этого элемента.
Куда уж безопаснее. :)
Тогда массив где-то хранить надо иначе при добавлении файлов ссылки поплывут.
Ну а как заинъектировать что-то, чего нет в нужной папке в этом случае - я не знаю. Даже если слеши не проверять - include("имяпапки\".$_GET['id'].".hml") или ругнётся или возьмёт что надо. Особенно если подпапок нет.
Ну для пущей перестраховки - перепровериться на слеши или удалить их.

DogEater
20.03.2010, 00:13
Массив поплывёт только если запрос был до изменения списка файлов.
Судя по задаче - набросать всего, а потом изредка докидывать - считай статичный контент.

Mirnyi
20.03.2010, 00:19
Массив поплывёт только если запрос был до изменения списка файлов.
Судя по задаче - набросать всего, а потом изредка докидывать - считай статичный контент.
он поплывёт если изменения внесены между отправкой ссылки и получением запроса.
Т.е. "прощай избранное и обмен ссылками"
Да и сегодня вообще "модно" когда ссылка осмысленная - при желании можно и без переменных вообще обойтись - прямо в путь имя файла прописывать, rewrite-ом перенаправлять :) (на апаче)

CoValent
20.03.2010, 11:30
Список у тебя на винте есть всегда.
Можно входящую строку проверить на слеши и сделать if fileexist()
А можно сделать list папки и сравнить поэлементно массив с входной строкой.
И так, и так никакая инъекция не пройдёт.
Нах...фига столько мучиться, если простой прямой вызов гораздо меньше мучений потребует, Андрюш?...

Тем более, что у меня из серьёзного программирования - только первое образование да HTML, и мне важнее сдать рабочий проект, чем углубиться в теоретические возможности? :D

Mirnyi
20.03.2010, 12:22
Нах...фига столько мучиться, если простой прямой вызов гораздо меньше мучений потребует, Андрюш?...

Тем более, что у меня из серьёзного программирования - только первое образование да HTML, и мне важнее сдать рабочий проект, чем углубиться в теоретические возможности? :D
Просто, прямой вызов, как я понял, ты хочешь делать в куче файлов контента, который будет изменяться, расширяться, дополняться. И эти прямые вызовы нужно запихнуть в каждый такой файл.
А можно, как ты вначале и собирался сделать один маленький шаблон, в котором 2 статических вызова и 1 динамический.

Не... Ну учить тебя делать проекты я не буду.:) Я сам готов поучиться и решение тебе принимать - просто предлагаю конкретное, маленькое решение как один из кучи вариантов.


<?php
include("header.htm");

if !(preg_match ("/[\/]/",$_GET['id'])){
if (is_file("folder\".$_GET['id'].".htm")){
include("folder\".$_GET['id'].".htm");
}
else{
include("folder\1.htm");
}
}
else {

include("folder\1.htm");
}

include("footer.htm");
?>
Через ?id="file" запрашиваешь нужный файл контента из папки "folder".
И получаешь готовую страничку.
Инъекция при таком раскладе не грозит. Безопасность на месте, весь контент лежит в одной папке, из соображений паранойи "только для чтения".

CoValent
20.03.2010, 12:42
Вооот! Так я об этом и говорил, Андрей - простое решение для простых задач. Мне оно очень понравилось! (И не в последнюю очередь из-за понимания процесса... :ups: :lol: )

Как вариант для сайтов-визиток можно даже не к папке привязываться, а к домену (благо, полсотни файлов в корне домена второго уровня - норма).

Спасибо ещё раз! :)

Нет, от работы точно надо отдыхать - а то в какой-то момент мозги кипят...

Mirnyi
20.03.2010, 15:06
тоже самое, но ещё короче :D


<?php
include("header.htm");
$file="folder\1.htm";
if ((!(preg_match ("/[\/]/",$_GET['id']))) & (is_file("folder\".$_GET['id'].".htm"))){
$file="folder\".$_GET['id'].".htm";
}
include($file);
include("footer.htm");
?>