Это копия, сохраненная 6 марта 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Предыдущий тред был тут: >>1109863 (OP). Остальные треды есть в архиве: https://phpclub.tech/ или ищутся в гугле по словам "клуб изучающих php" и в архиваче.
Мейлач лежит? Есть запасной тред на доброчане: /s/res/23225.xhtml#i46467
Что самое главное для программиста? Умение аккуратно оформлять код (как, написано во втором посте).
Правила: ведем себя воспитанно, помогаем новичкам, читаем учебники, решаем задачки, постим ссылки на решения, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
С чего начать
У нас есть свои уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то можно начать с него. Он простой и понятный. Там есть задачи, их нужно решать (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению. С другой стороны, если этот учебник тебе не нравится, можно читать любой другой. Или официальный мануал. Или все сразу.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка PHP, этого недостаточно. Вот что в идеале надо изучить еще: ООП, как работает веб-сервер, HTML/CSS, SQL, PDO, работа с таблицами в БД, работа с формами, MVC, git, composer, JS, фреймворки, автоматизированное тестирование.
Надо переходить к более серьезным задачкам, которые научат тебя всему этому.
- для начала прочти урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- установи Апач + PHP (советы выше и ниже) и читай туториал http://php.net/manual/ru/tutorial.php
- Учи HTML/CSS и SQL, PDO, хотя бы основы
- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Symfony: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование https://gist.github.com/codedokode/a455bde7d0748c0a351a
- Если ты все решил, переходи к Symfony 3/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://github.com/codedokode/pasta/blob/master/db/databases.md
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.
Платиновые вопросы
- Почему PHP? Потому что вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery. У нас в треде были люди, которые практически с нуля учились и смогли найти работу.
- Что будут спрашивать на собеседовании если 0 опыта - гонять по теории, по официальному мануалу PHP, давать дурацкие задачки на переворачивание строк, гонять по SQL (транзакции, внешние ключи, напиши запрос), по JS (как сделать анимацию при нажатии кнопки), ну погугли, не ленись
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.
Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492
Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:
- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)
Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:
PSR-1: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
>>1117075 >>1117974 7 янв https://github.com/moabit/student-list
>>1118051 10 янв https://github.com/TheSidSpears/testhub/
Уже проверил:
- https://github.com/pmaprog/codedokode-html - тут >>1117863
- https://github.com/dsgaljkeguhodgiosetuhsegjposguh/studlist2 - тут >>1118527 >>1117864
Напомню, что стоит не откладывать на потом изучение английского. Читать можно news.ycombinator.com - это что-то вроде их хабра.
Если я кому-то не ответил в прошлом треде, напомните о себе тут.
Суть такова.
Допустим есть карта (просто jpg изображение на котором карта ).
Нужно поверх этого изображения разместить ещё 40-50 мелких изображений (20*20px).
При этом если первое изображение карта занимает всю страницу, то другие изображения будут мелкими типа маркеров на гуглмапсе.
При это каждое из 40 мелких должно иметь свои координаты.
В прошлом треде мне помогли с координатами z index и CSS скинув очень годные ссылки.
Эти
https://www.w3schools.com/cssref/pr_pos_z-index.asp
https://www.w3schools.com/css/css_positioning.asp
Но теперь вопрос как будет лучше это всё размещать так чтобы небыло говнокода. И при этом работало.
Например есть карты с 59 обьектами (или 23, или вовсе 2 чтобы вы поняли). Я скриптом прохожусь чтобы узнать количество обьектов, потом формирую страницу, и сразу генерирую CSS встроенный в страницу чтобы создать 59 обьектов и сразу дать им координаты? Или можно это всё сделать по другому, например через JS?
Я не смог применить эти функции, у меня с ними не работает и я так до конца и не понял, каким образом их использовать.
>>1118475
>Ты каждый раз заполняешь строку в ручную, а нужно делать это программно, чтобы программа работала с заведомо неизвестным количеством массивов и элементов
Ну эту проблему я тоже не смог решить, до оепратора точка не додумался.
>>1118548
>// Идем по массиву массивов слов и на каждом шаге выбираем 1 слово
foreach ($allWords as $variants) {
var_dump($variants);
}
Но как он будет случайные слова подбирать? Он же их просто перебирает.
Зарандомь $variants и выводи в нужном тебе порядке результат
Вопрос, как ты хранишь эти изображения и их координаты?
Думаю, лучше делать это через js, можно с использованием canvas. https://www.html5canvastutorials.com/tutorials/html5-canvas-image-loader/
Для твоей задачи на js есть много библиотек, например https://github.com/d3/d3/wiki/Gallery
https://ideone.com/YMAqiv
Ниже функции пока не пробовал применить, ща буду макакить
>foreach ($allWords as $variants) {
var_dump($variants);
Дополню, что по условиям должно быть
>words1, words2, word3
>words1, words2, words3
>words4, words5
то есть четко поставлены условия, из каких массивов должны быть взяты рандомные слова.
echo $second[$n],"-",$first[$k]," ", <a href='"https://example.ru/?callback=search&country={$did}&city={$id}\n"'></a>;
не работает.
>Я не смог применить эти функции, у меня с ними не работает и я так до конца и не понял, каким образом их использовать.
вместо
$element = count($words['word1']);
$r = mt_rand(0,($element - 1));
$b = $words['word1'][$r];
echo "$b ";
можно написать
echo $words['word'1][array_rand($words['word'1])] . ' ';
Прочитать документацию. Вроде даже русский перевод доступен.
Ну и конечно, надо знать HTML и CSS.
Правда, я попробовал почитать, русский перевод очень плохой, и сделан явно через Гугл Translate (и это не мешает сайту быть в топе выдачи). Так что по возможности лучше читать исходную документацию на английском.
вопрос сам по себе не тупой, но, мне кажется, нет смысла задавать тут вопросы, на которые можно найти ответ в первой строчке гугла
https://mariadb.com/kb/en/library/mariadb-vs-mysql-features/
Вопрос стоит ли вкатиться в php? (в основном из-за большего количества как вакансий, так и заказов на фрилансе)
И смогу ли уложиться в 3 месяца (начинаю прям щас), если буду ебашить прерываясь только на поспать и посрать?
что думаете по поводу такого решения? в задании говорилось про цикл, но я не понял, как его там задействовать
А можно эту задачку на laravel запилить?
Язык не нравится. Как сишника, отталкивает буквально всё. Но учу. Зачем? Потому что простой. Потому что хочу понимать различные технологии, а не говноедствовать, задрачивая на один язык.
>Вопрос, как ты хранишь эти изображения и их координаты?
Изображения - это просто jpg. Координаты в базе данных, 2 поля x и y.
Нет. Я не знаю, как это делается.
Логика такова: я получаю массив таблиц с результатами sql-запросов.
Из этого надо сделать массив из значений, находящихся в таблицах.
Можно ли написать этот код без трех циклов, вложенных друг в друга?
Сразу скажу: 2 скобки просто не добавил в код, но так они у меня есть и все работает.
Насколько я понял, докер разворачивает каждый процесс как отдельный контейнер, и так как я думал: nginx + php-fpm + mysql в одном контейнере не выйдет, или я ошибаюсь? Или посоветуйте что-то для быстрого деплоя/развертывания одного проекта на N-нод
Да
>>18617
http://archive-ipq-co.narod.ru/l1/strings.html
>Подсказка: так как первая и вторая строка формируются по одинаковому принципу, то незачем копировать код 2 раза, можно использовать цикл из 2 шагов.
Тебе просто нужно выполнить два раза циклом склеивоние 1-ых по 3-их слов и добавить перенос строки, и затем отдельно вначале добавить "Я", и склить 4-ые и 5-ые
>>18618
>Подсказка: можно упростить программу, сделав что-то вроде шаблона для генерации стиха на основе массива. В каждый элемент массива мы кладем массив вариантов слова или строки, из которого надо сделать выбор: [$word1, $word2, $word3, ["\n"], ...]. Мы добавляем массив с "\n", чтобы в нужном месте вывелся перевод строки. Остается только пройти по массиву циклом и сгенерировать стих..
В этом случае можно будет воспользоваться foreach
>>18638
https://3v4l.org/Qk3jJ
>Parse error: syntax error, unexpected '<' in /in/Qk3jJ on line 3
Нужно заключить её в ковычки
>>18846
Другое дело
>в задании говорилось про цикл, но я не понял, как его там задействовать
Он нужен чтобы не повторять одни и те же строки дважды
>$piece1 = array_rand($word1);
>$piece2 = array_rand($word2);
>$piece3 = array_rand($word3);
//тут тоже
>$piece4 = array_rand($word1);
>$piece5 = array_rand($word2);
>$piece6 = array_rand($word3);
>$pieceOfPoem1 = $word1[$piece1] . $word2[$piece2] . $word3[$piece3];
>$pieceOfPoem2 = $word1[$piece4] . $word2[$piece5] . $word3[$piece6];
Так же, код можно упростить $word1[array_rand($word1)]
У тебя проблемы с циклами и массивами - изучи уроки по ним ещё раз
>>18954
Скинь массив результата таблицы
Да
>>18617
http://archive-ipq-co.narod.ru/l1/strings.html
>Подсказка: так как первая и вторая строка формируются по одинаковому принципу, то незачем копировать код 2 раза, можно использовать цикл из 2 шагов.
Тебе просто нужно выполнить два раза циклом склеивоние 1-ых по 3-их слов и добавить перенос строки, и затем отдельно вначале добавить "Я", и склить 4-ые и 5-ые
>>18618
>Подсказка: можно упростить программу, сделав что-то вроде шаблона для генерации стиха на основе массива. В каждый элемент массива мы кладем массив вариантов слова или строки, из которого надо сделать выбор: [$word1, $word2, $word3, ["\n"], ...]. Мы добавляем массив с "\n", чтобы в нужном месте вывелся перевод строки. Остается только пройти по массиву циклом и сгенерировать стих..
В этом случае можно будет воспользоваться foreach
>>18638
https://3v4l.org/Qk3jJ
>Parse error: syntax error, unexpected '<' in /in/Qk3jJ on line 3
Нужно заключить её в ковычки
>>18846
Другое дело
>в задании говорилось про цикл, но я не понял, как его там задействовать
Он нужен чтобы не повторять одни и те же строки дважды
>$piece1 = array_rand($word1);
>$piece2 = array_rand($word2);
>$piece3 = array_rand($word3);
//тут тоже
>$piece4 = array_rand($word1);
>$piece5 = array_rand($word2);
>$piece6 = array_rand($word3);
>$pieceOfPoem1 = $word1[$piece1] . $word2[$piece2] . $word3[$piece3];
>$pieceOfPoem2 = $word1[$piece4] . $word2[$piece5] . $word3[$piece6];
Так же, код можно упростить $word1[array_rand($word1)]
У тебя проблемы с циклами и массивами - изучи уроки по ним ещё раз
>>18954
Скинь массив результата таблицы
если видел большие проекты, то хватит
>>19002
Тебе нужно запустить веб-сервер
У PHP есть собственный встроенный
https://secure.php.net/manual/ru/features.commandline.webserver.php
Так же, у нас есть урок по установке и настройке PHP и сервера
https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/web-server.md
Благодарю, добра тебе.
Чтобы Апач выполнял PHP код, а не отдавал, нужно:
- установить PHP на компьютер
- в конфиге Апача подгрузить модуль mod_php и прописать, что PHP файлы должен обрабатывать он
Директивы для конфига Апача можно найти тут http://php.net/manual/ru/install.unix.apache2.php
Если ты запускаешь простые скрипты, то тебе может быть проще просто использовать встроенный в PHP веб-сервер как описано по ссылке, которую дал анон выше.
есть код
<div class="sidebar-module">
<ol class="list-unstyled">
<li><a href="#">October 2013</a></li>
</ol>
</div>
я допустим хочу сделать стайл для всех ссылок, которые лежат в диве с классом sidebar-module
пишу в style.css
a.sidebar {color: #555;}
но нихуя не работает. подскажите, что в стайл прописать
.sidebar-module a {color: #555;}
Гугли наследование css селекторов, поймёшь всё очень быстро. Если коротко, то ты даёшь стиль элементу а внутри класса sidebar-module, а если ты напишешь a.sidebar-module, то получиться, что ты даёшь стиль всем элементам a с классом sidebar-module.
благодарю!
Знаю элемент button, но нигде не видел связанных с ним внятных статьей или хорошего кода
быстрофикс
анон, я разобрался и программа получилась на столько короткой, что я просто ахуел, спасибо
https://ideone.com/4OINVC
>сбрасываешь стили
>ставишь дисплей блок
>оформляешь как обычный див
>profit...
Мимо вкатывальщик из фронт-энд треда, а еще есть фреймворки типа бутстрапа...
Смысл вкатываться через две недели. Мне вот надоедает дрочить верстку долго, жс тоже надоедает дрочить. Поэтому обмазываюсь ими по очереди.
http://sandbox.onlinephpfunctions.com/code/59ad0f4278069af0ceacfc199c6d4518b6cd0aff
А получить через контейрнер его я там не вижу как. То это хуевая реализация. Или мне создать свой пдо в нем?
Разве ты не регистрируешь __invoke() класс в контейнере прежде чем добавить его в промежуточный слой?
В нём и добавляй все зависимости через конструктор.
Должно получиться.
Нет, у тебя там 3 функции с одинаковым кодом, это плохо - копипаста. У тебя должна быть одна функция, а переменные, которые ты задаешь в начале, должны передаваться через аргументы.
А что такого? Вообще нейросети довольно старое понятие, их ещё в прошлом веке наверное с 60ых годов разрабатывали, потом хайп ушел так как не хватало мощностей, сейчас вторая волна началась (может и не вторая, а N-волна). Во-вторых кому-то надо будет поддерживать эту верстку, кому-то надо будет работать с самими нейронками, заказчики сами этого не сделают. Я глазами пробежал, там только статика? Сейчас любой сайт, это наполовину js-приложение, которое без js зачастую просто развалится либо превратится в тыкву. Ну и в третьих, это даже хорошо когда механические задачи больше не надо будет делать.
Удобно, че
спасибо анон. вообще я сразу так не делал потому что в документации он примерно вот так делает
$app->add( new NEwMiddleware());
смог, хотя не уверен, что это именно то, что ты имел ввиду типа цикл в цикле получился
https://ideone.com/Ehcsuj
по правде говоря, тот самый "верстальщик", который 10 лет назад верстал статику, уже не существует в природе. щас любую статику можно сделать быстро и без гемора с помощью существующих инструментов (бутстрап, например) при наличии минимального опыта. то есть, такой профессии уже давно нет, сейчас есть фронты.
У тебя получилось?
Прежде чем создать какой-то сервис нужно зарегистрировать его в контейнере. Но это не точно.
>>19358
>хотя не уверен, что это именно то, что ты имел ввиду
В задаче сначала был массив массивов $words с всеми словами
В посте >>18981 есть подсказка как решить такую задачу
>>Подсказка: можно упростить программу, сделав что-то вроде шаблона для генерации стиха на основе массива. В каждый элемент массива мы кладем массив вариантов слова или строки, из которого надо сделать выбор: [$word1, $word2, $word3, ["\n"], ...]. Мы добавляем массив с "\n", чтобы в нужном месте вывелся перевод строки. Остается только пройти по массиву циклом и сгенерировать стих..
Лучше не к фреймворкам привязываться, а делать упор на фундаментальные вещи - сети, ООП, линукс. Я к примеру устраивался Symfony джуном и за полгода успел поработать с Laravel, Yii2, Zend. При том, что ранее с этими фреймворками знаком не был.
Вроде, даже можно просто написать просто $app->add('newMiddleware') если оно зарегистрировано в контейнере.
рли сработало. спасиб анон
Вот именно. Плотники и обработчики металла не исчезли с появлением станков и циркулярных пил.
пхп как бы не только в окошечке браузера работает. большую часть современных больших приложений составляют cli-скрипты.
также потому что ты будешь подключаться по ssh к удаленному серверу, который на линуксе.
плюс гит. плюс баш-скрипты автоматизации на дев-сервере. плюс перезапуск сервисов, сборка фронта, еще куча всего.
учитывая, что я тебе говорю про удаленный сервер, не работает, т.к. такой вещи как винда+пхп на продакшне не существует.
>пишите один большой пост вместо нескольких маленьких
Лол, как в исходники Moodle заглянул.
И не говори. Никто не заставляет учить, и в итоге получается так что пердолишься в лучшем случае 15 часов в месяц
Кто хочет поучаствовать в пет-проекте за опыт напишите в телегу @monada
>> устраивался Symfony джуном
> какие вопросы задавали на собесе?
Конкретно по Symfony не спрашивали ничего серьёзного - какие FormType использовать если есть сущность и связанные с ней через 1:M другие сущности, какие существуют способы описания метаданных сущностей, в чём преимущества недостатки у каждого из способов, какие бандлы юзал и т.д.
Больше было общих вопросов, например как работают сессии, что такое DNS, зачем используются трейты/итераторы/генераторы, магические методы, какие новые фичи в PHP7. Тестовые задания не просили делать, видимо из-за аккаунта на гитхабе, но было пару задачек на проектирование простой иерархии классов и на рекурсивный обход массива (у ОПа как раз есть эта похожая задача: https://github.com/codedokode/pasta/blob/master/interview-tasks.md#Дерево ). Код на листочке не писал (как этим любят запугивать в перезвоним-тредах), описывал алгоритмы словами.
По JS - чем отличаются call и apply, почему теряется this, что нового в ES6, что такое прототипы (ни разу не юзал их за всё время что работаю, но на собесе ответил, так как решал здесь задачи). Ещё немного тут писал: https://phpclub.tech/pr/res/1067944.html#1075232
спасибо. судя по вопросам, должна быть хорошая контора.
щас сам симфони учу, начал сразу как вышла 4. очень интересно, но местами сложновато и неочевидно.
а что ты имеешь в виду под метаданными? записи типа @ORM\Table(name="blog") или что-то другое?
preg_replace(array("`'`", "`[^A-z0-9]+`"), array("", "-"), $str)
точно блин
Полагаю автор соснул. Его использование обратной кавычки делало код бесполезным для санации строки.
https://phpclub.tech/pr/res/1109863.html#1117076
скинь
любой напиши обсудим
В том и дело, хотел пообщаться с кем-то по поводу докера и систем виртуализации в целом, но никто не отвечает. В чате может быстрее это произошло бы
есть. тут даже был один, который пытался версию пхп обновить что ли. просто я к тому что это не повод не учить линукс в надежде, что попадется виндос сервер (который поди еще замороченнее линукса в изучении).
@monada напиши добавлю в конфу
Необходимо написать скрипт парсера, который будет выполняться несколько дней неиспользуйпхпшники идут нахуй.
Проблема в том, что во время выполнения скрипта может произойти где-то ошибка, например мне нужно писать спрасеное в удаленные БД, где админы любят мутить всякую хуйню из-за чего порой можно не получить соденения с базой. Либо еще какойто ноунейм fatal error.
Соответственно скрипт упадет. А мне этого ненужно.
Пишу перехватчики через set_error_handler() и set_exception_handler() при получении ошибки - шлю к себе на почту. Но как быть в случае fatal error? Как сделать так, чтобы при получении таковой ошибки скрипт продолжил выполнение?
Можно конечно обвешать все try catch throwable, но это хуита ибо не всего не учесть. Ваши предложения?
ошибся, хотел справа поставить тоже две.
вот тут у меня основной вопрос: одна палочка значит "один", а две - "один и только один". в чем разница между ними?
>один и только один
Попахивает индексом Unique для поля в БД. В принципе, в твоем случае идентификация происходит по Primary key а он всегда unique. А какой программой ты пользуешься для моделирования?
https://www.lucidchart.com/ попал туда с туториала https://www.youtube.com/watch?v=-CuY5ADwn24
но я уже не уверен, что это относится к проектированию бд.
>>19959
да.
новые проекты на пхп не пишут, вкатывайся.
>но я уже не уверен, что это относится к проектированию бд.
это я имел в виду про одинарную черточку, т.к.
они там моделируют далеко не только бд. возможно в бд достаточно обозначить тип связи и все
>public function setRank(int $rank): void
>{ $this->rank = $rank; }
Правильно ли я понял, что ПХП внезапно стал языком со строгой типизацией?
Может быть и не знаю, но вопрос тем не менее остаётся в силе, с каких пор в пхп можно или нужно указывать типы данных при объявлении функций?
Очевидно с 7 версии.
Не вижу там возможности экспорта схемы БД. Подобный софт должен это делать в форматах SQL и XML, да еще и с тестовыми данными, как это делает Sybase Power Designer. А в идеале он еще должен генерировать классы для работы с базой и фреймворка, как это делает Skipper (ORM Designer), но для него кряка нет, а он стоит баков 300 отсоси у тракториста.
Есть у меня допустим страница с кнопками от бутстрапа. Есть файл php скрипта.
Как их законектить самым простым способом? Чтоб при нажатии на кнопку выполнялся скрипт.
Гуглением нашел всякие ассинхронные фреймворки, но мне нужен максимально простой способ.
Или хотя бы хороший пример - потому что в гугле тонна примеров сабмит формы, но мне это не очень подходит.
>try catch throwable, но это хуита ибо не всего не учесть.
Это ты хуита. PDO кидает исключение, если база не доступна, его и обрабатывай.
Уже пару часов не могу доту пить как же сделать переборку слогов, через foreach? ЧЯДНТ?
-можешь положить все кнопочки в форму в которой у тебя прописан action='твой скрипт'
-Можно с помощью жквери. Типа присваиваешь функцию кнопочке, а в функции у тебя аякс.
>$randomText = array();
>foreach ($letters as $randomText);
>$randomText = implode($letters);
Во первых учи PSR и юзай скобки!!!
Во вторых, у тебя тут цикл по пустому массиву $randomText, чего ты ожидаешь?
Во третьих, ты украл чей то код?
>/ Выкидываем случайное число (count - число элементов в массиве) /
>/ Точка склеивает 2 строки в одну /
Эти комменты указывают на вещи которые не используются в коде, а должны бы.
>Во вторых, у тебя тут цикл по пустому массиву $randomText, чего ты ожидаешь?
Что я несу, совсем обджиэсился.
У тебя цикл по ВСЕМ слогам,
$randomText это переменная цикла - значение каждого слога,
но в цикле ты присваиваешь ей новое значение, что бессмысленно
Есть сайт на одной из страниц которого лежат изображения, нужно их заменить на новые.
Скачал фтп, все залез, нашел где лежат данные картинки.
Но не могу найти файл где они прописаны что они должны находится на именно той странице сайта (не знаю как правильно объяснить но вы поняли)
Т.е на сайте они лежат по адресу www.site/wp-content/uploads/2011/12/filename.jpg
На фтп они там есть. Искал через notepad++ во всех файлах упоминание filename.jpg, его там тупо нету. Что я делаю не так?
Я знаю, но это опциональное применение. Товеть ты можешь это применять, а можешь и нет.
они там поди генерятся динамически и их названия лежат где-то в бд в отдельной ячейке или генерятся по названию статьи, хз. может кто-то, знающий вп, ответит более конкретно
да, просто эта возможность тесно связана с тайп-хинтом аргументов и возврата, о котором спрашивал анон.
алсо, я тут пытаюсь использовать эту строгую типизацию, она конечно прикольная, но какая-то недоделанная по сравнению с джавой. нельзя указать тип переменной например int $count; надо писать обязательно $count = 0; но это хуета в принципе, а вот что нельзя сделать массив строк или массив интов - это недоработка по мне.
плюс есть некоторые функции, которые исторически выдают либо фолс, либо тру, либо число, либо массив. допустим preg_replace возвращает либо массив, либо строку, либо нулл.
Это же пример с гайда по обучению,который здесь лежит. Просто поленился комменты тереть.
вордпресс
оно на то и фатал еррор, чтобы останавливать программу. можешь свечку поставить, чтобы он не вываливался лол
>нельзя указать тип переменной например int $count;
Чел ну это не недоделанность, это другой синтаксис. А ты что думал, что выучишь джаву и всё? Везде так будет?
Так я и пытался через выгрузку в пустой массив отдельных слогов запилить склейку имени. Но что-то пошло не так.
>выучишь джаву и всё?
вообще было бы круто лол
это понятно, но в джаве можно написать int a, b, c; а у нас как? только через жопу типа $a = $b = $ c = 0;
Видимо ты не правильно пользуешься функцией preg_replace. Так как регулярные выражения в php работают очень хорошо и никаких проблем не вызывают
preg_replace() возвращает массив, если параметр subject является массивом, иначе возвращается строка.
Если найдены совпадения, возвращается новая версия subject, иначе subject возвращается нетронутым,
в случае ошибки возвращается NULL.
Можно написать так:
$a = 0;
$b = 0;
$c = 0;
Нет никакой необходимости объявлять несколько переменных в одной строке.
Не стоит так в нашем треде разговаривать. Тебе ведь никто помогать не захочет.
По поводу исключений, у меня есть урок (если он вдруг нужен): https://github.com/codedokode/pasta/blob/master/php/exceptions.md
Так вот, исключения тем и отличаются от ошибок PHP, что в случае их возникновения PHP выходит из функции вверх (в вызвавшую фукнцию), из нее еще вверх и так, пока не наткнется на catch или не выйдет на самый верх. Это поменять нельзя.
В случае обычных ошибок принцип другой - при ошибке вызывается обработчик, и есть выбор, завершить скрипт либо проигнорировать ошибку. Опции "повторить проблемную команду" нет и там.
Тебе придется править код программы и добавлять повтор попыток явно. По моему, проще просто настроить БД нормально (или запускать скрипт у себя, где ничего не отвалится). Иначе надо искать все места в скрипте, где идет обращение к БД и заменять стандартные функции на свои, которые будут ловить исключение и при его возникновении делать повторное соединение к БД. желательно ограничить число попыток.
Ну и что в этом такого необычного? В php это обычная практика делать функции, которые возвращают разные типы данных в зависимости от различных параметров.
У ответа ведь все равно всегда можно проверить тип данных при помощи функций is_bool, is_double, is_string, is_array и так далее.
это просто пример того, что встроенные функции под возврат нужного типа не приспособлены. таких примеров много. в случае с preg_replace можно возразить "ну шли туда всегда строку и будет возвращаться строка", но тут другой нюанс: допустим, я хочу обернуть логику в свой метод, в других языках для обработки разных типов данных есть перегрузка, а тут ее нет, придется писать replaceString(), replaceArray()
>>20246
убедил лол
я вообще это не к тому, что все плохо, а к тому, что еще есть что допилить в направлении строгой типизации.
Суть программирования в том, что тебе надо написать решение задачи в виде набора шагов, которые поймет компьютер. Он твои мысли читать не может и не угадывает, что ты имел в виду, а выполняет программу строго, как она написана.
Ты можешь для начала расписать, что должно делаться внутри цикла, на русском языке? Чтобы было видно, где проблема - ты не понимаешь, какие действия надо сделать, или же ты понимаешь, но не знаешь, как их записать на языке PHP?
По твоему коду, у меня ощущение, что ты просто там писал наугад команды в надежде, что оно как-то заработает. Увы, так это не работает. Нужно понимать, что делает каждая строчка.
Я дам тебе пример, как сгенерировать имя из 2 цифр (согласен, странное имя, но это ради простоты):
$number1 = сгенерировать случайную цифру от 1 до 6;
$number2 = сгенерировать случайную цифру от 1 до 6;
$result = склеить $number1 и $number2 в одну строку;
вывести $result;
И теперь перевод этого кода на PHP:
$number1 = mt_rand(1, 6);
$number2 = mt_rand(1, 6);
$result = $number1 . $number2;
echo $result;
echo "\n";
Заметь, что у меня нет цикла. Это для простоты. Я сначала написал простое решение без цикла и для 2 слогов, а потом могу переделать на цикл с любым числом повторений. Ты можешь сделать так же, сначала без цикла, с 2 слогами, а потом уже сделать нормально.
Попробуй свое решение записать так же. Если ты не понимаешь, какие должны быть шаги, напиши, дадим еще подсказки.
Суть программирования в том, что тебе надо написать решение задачи в виде набора шагов, которые поймет компьютер. Он твои мысли читать не может и не угадывает, что ты имел в виду, а выполняет программу строго, как она написана.
Ты можешь для начала расписать, что должно делаться внутри цикла, на русском языке? Чтобы было видно, где проблема - ты не понимаешь, какие действия надо сделать, или же ты понимаешь, но не знаешь, как их записать на языке PHP?
По твоему коду, у меня ощущение, что ты просто там писал наугад команды в надежде, что оно как-то заработает. Увы, так это не работает. Нужно понимать, что делает каждая строчка.
Я дам тебе пример, как сгенерировать имя из 2 цифр (согласен, странное имя, но это ради простоты):
$number1 = сгенерировать случайную цифру от 1 до 6;
$number2 = сгенерировать случайную цифру от 1 до 6;
$result = склеить $number1 и $number2 в одну строку;
вывести $result;
И теперь перевод этого кода на PHP:
$number1 = mt_rand(1, 6);
$number2 = mt_rand(1, 6);
$result = $number1 . $number2;
echo $result;
echo "\n";
Заметь, что у меня нет цикла. Это для простоты. Я сначала написал простое решение без цикла и для 2 слогов, а потом могу переделать на цикл с любым числом повторений. Ты можешь сделать так же, сначала без цикла, с 2 слогами, а потом уже сделать нормально.
Попробуй свое решение записать так же. Если ты не понимаешь, какие должны быть шаги, напиши, дадим еще подсказки.
Я к тому, что я смог найти это в доках за 5 секунд. PHP не идеален, но блин вот эта функция по моему работает вполне внятно. Ладно не буду превращать тред в чатик.
Например тут
function trim_value(&$value)
{
$value = trim($value);
}
Я бы бы через foreach перебрал. Чем мой вариант хуже кроме того что он длиннее?
>в других языках для обработки разных типов данных есть перегрузка
В php конечно же нет перезагрузки функций, т.е. создание функций с одинаковыми названиями, но разными параметрами. Но этого обычно и не требуется, так как во-первых, можно объявить параметры с default-значениями:
function func($int, $string = ''),
а еще можно проверять тип данных параметра:
function func2($var) {
if (is_array($var)) //сделай это
else if (is_string($var)) //сделай что-то другое
else //сгенерируй сообщение об ошибке
}
Обе эти возможности на 100% заменяют перезагрузку функций.
PHP называют языком с "добровольной типизацией" - кто хочет, тот и ставит тайп-хинты. Тайп-хинты можно ставить на аргументы и результат функций но, увы, нельзя на поля и переменные. Также, увы, тайп-хинты ограничены в возможностях и пока нет generics.
Как видишь, с тайп-хинтами код становится намного лучше, так что советую ставить их везде.
>>20216
Замечу, что эта опция влияет только на отключение преобразования типа в тайп-хинтах. Мне она не нравится тем, что теперь у нас может быть 2 вида исходников, в одних все совсем строго, в других не совсем. Опять они не смогли выбрать одно решение и решили всем предложить выбор.
>>20236
Для массива строк или интов, или коллекции каких-то объектов нужны generics:
https://wiki.php.net/rfc/generic-arrays
https://wiki.php.net/rfc/generics
Эти предложения пока не приняты, и код, как я понимаю, не написан. Но все еще возможно.
> плюс есть некоторые функции, которые исторически
Это не мешает тебе писать свои функции со строго определенными типами.
> недоделанная по сравнению с джавой
Ну это все таки другой язык. Если ты хочешь как на Джаве, то проще на ней и писать.
>>20244
По моему субъективному мнению, отсутствие единого типа аргументов или результатов ухудшает код и повышает вероятность ошибок. Я бы сделал для массивов отдельную функцию preg_replace_array.
А вот возвращать что-то или null вполне допустимо. null для этого и придуман.
>>20251
По моему субъективному и ничем, кроме моего опыта, не подкрепленному мнению, это плохо. Нельзя же писать нормально код, когда ты не уверен, какого типа результат. Нужно строго определять типы аргументов и результата, если они могут быть разные, лучше сделать несколько разных функций. Иначе легко ошибиться.
Ну и разным анализаторам кода тоже будет легче.
PHP называют языком с "добровольной типизацией" - кто хочет, тот и ставит тайп-хинты. Тайп-хинты можно ставить на аргументы и результат функций но, увы, нельзя на поля и переменные. Также, увы, тайп-хинты ограничены в возможностях и пока нет generics.
Как видишь, с тайп-хинтами код становится намного лучше, так что советую ставить их везде.
>>20216
Замечу, что эта опция влияет только на отключение преобразования типа в тайп-хинтах. Мне она не нравится тем, что теперь у нас может быть 2 вида исходников, в одних все совсем строго, в других не совсем. Опять они не смогли выбрать одно решение и решили всем предложить выбор.
>>20236
Для массива строк или интов, или коллекции каких-то объектов нужны generics:
https://wiki.php.net/rfc/generic-arrays
https://wiki.php.net/rfc/generics
Эти предложения пока не приняты, и код, как я понимаю, не написан. Но все еще возможно.
> плюс есть некоторые функции, которые исторически
Это не мешает тебе писать свои функции со строго определенными типами.
> недоделанная по сравнению с джавой
Ну это все таки другой язык. Если ты хочешь как на Джаве, то проще на ней и писать.
>>20244
По моему субъективному мнению, отсутствие единого типа аргументов или результатов ухудшает код и повышает вероятность ошибок. Я бы сделал для массивов отдельную функцию preg_replace_array.
А вот возвращать что-то или null вполне допустимо. null для этого и придуман.
>>20251
По моему субъективному и ничем, кроме моего опыта, не подкрепленному мнению, это плохо. Нельзя же писать нормально код, когда ты не уверен, какого типа результат. Нужно строго определять типы аргументов и результата, если они могут быть разные, лучше сделать несколько разных функций. Иначе легко ошибиться.
Ну и разным анализаторам кода тоже будет легче.
ну ладно
Ссылки в php нужно использовать как можно реже или лучше даже совсем от них отказаться.
А может ты тогда напишешь код (внутри цикла) на русском и на PHP, а я или кто-то еще скажет, где ты ошибся при переносе с русского на PHP?
>>20262
В твоем примере, лучше возвращать результат, а не менять аргумент, так как это выглядит более ожидаемо, что функция вернет что-то.
Насчет ссылок, в мануале описано, что у них много подводных камней, потому лучше не использовать их без надобности: http://php.net/manual/ru/language.references.php
>>20217
Контент (в том числе HTML код статей) может храниться в базе данных. Редактировать их можно в случае вордпресса через админку, в которую тебе должны были выдать доступ.
Но ты можешь заменить файлы картинок, оставив те же самые имена.
>>20268
У нас обучающий тред, желательно писать, почему. А то без аргументов выглядит как чье-то личное мнение.
>Какое ВП? Какая база, поехавший?
а, это я не тебе. это я >>20217 анону
алсо, валерианочку попей.
>>20265
>Если ты хочешь как на Джаве, то проще на ней и писать
туда хер вкатишься. сам язык не сильно сложнее пхп, но экосистема просто безумно большая.
плюс если перекатываться, там будет явно меньше зп вначале, но это уже для другого треда разговор.
>Редактировать их можно в случае вордпресса через админку, в которую тебе должны были выдать доступ.
Не совсем понял, но полный доступ к хостингу, фтп вот к этому всему есть.
Пикрил - список плагинов.
Да, я так уже и сделал - заменил изображения на новые с такими же именами, но одно изображение исчезло (пустое место) но кликабельность и ссылка на него осталась, блин
https://ideone.com/IlvuRW
Не понимаю как из $letters перетащить данные последовательно по слогу. Поэтому собственно и спрашивал о переборке через foreach.
Бтв. Первые джва дня пытаюсь вкатится, поэтому скорее всего много глупостей говорю.
>>У нас обучающий тред, желательно писать, почему. А то без аргументов выглядит как чье-то личное мнение.
>У нас обучающий тред, желательно писать, почему. А то без аргументов выглядит как чье-то личное мнение.
Причина очень проста. Использование ссылок делает код более трудным для понимания и для поддержки, не давая почти ничего взамен
Странно, что ты никогда не слышал про админки. Там на сайте есть форма входа, вводишь туда логин и пароль и получаешь доступ. Попроси у заказчика "логин и пароль администратора сайта" и адрес страницы, куда его вводить. Они же как-то эти статьи туда добавили.
>>20273
Я напишу, что на самом деле делает код
// Берем случайный элемент массива и сохраняем в random его ключ (не значение, то есть не сам слог)
$random = array_rand($letters);
// Создаем пустой массив и помещаем в переменную
$randomText = array();
// склеиваем все 16 слогов из массива letters в одну длинную строку и помещаем в randomText,
// удаляя хранившийся там ранее массив
$randomText = implode($letters);
Соответственно, тебе надо немного вернуться и повторить такие вещи:
- что массив состоит из элементов, у каждого есть ключ (=индекс) и значение. Ключи уникальны и не повторяются внутри одного массива.
- как, имея массив слогов и ключ одного слога, получить значение этого слога? Подсказка: использовать квадратные скобки. Может, в уроке это плохо описано, но конструкция вида массив[ключ] возвращает значение элемента с данным ключом. Здесь "ключ" может быть переменной, числом, строкой в кавычках, сложным выражением.
- далее, получая на каждом шаге цикла один слог, как их собрать в массив? Надо до цикла создать пустой массив, а в цикле добавлять в него еще один элемент. Добавление элемента в массив (внутри цикла) делается так: массив[] = значение; При этом ключ для нового элемента генерируется автоматически. Ну а после цикла ты уже можешь склеить собранные слоги из массива в одну строку.
То есть, ты плоховато знаешь работу с массивами и отсюда проблемы.
Давай после задачки про слоги решим дополнительную задачку, чтобы лучше в них разобраться. Дано 2 массива с оценками за январь и за февраль вида:
$january = [
'math' => 4,
'physics' => 5,
'literature' => 2
];
$february = [
'math' => 5,
'physics' => 5,
'literature' => 2
];
Напиши программу, которая выведет:
- по каким предметам оценки остались неизменными
- по каким улучшились
- по каким ухудшились
Выводиться данные должны сгруппированно, в таком виде:
Оценки не изменились: physics, literature
Оценки улучшились: math
Оценки ухудшились: (таких нет)
Странно, что ты никогда не слышал про админки. Там на сайте есть форма входа, вводишь туда логин и пароль и получаешь доступ. Попроси у заказчика "логин и пароль администратора сайта" и адрес страницы, куда его вводить. Они же как-то эти статьи туда добавили.
>>20273
Я напишу, что на самом деле делает код
// Берем случайный элемент массива и сохраняем в random его ключ (не значение, то есть не сам слог)
$random = array_rand($letters);
// Создаем пустой массив и помещаем в переменную
$randomText = array();
// склеиваем все 16 слогов из массива letters в одну длинную строку и помещаем в randomText,
// удаляя хранившийся там ранее массив
$randomText = implode($letters);
Соответственно, тебе надо немного вернуться и повторить такие вещи:
- что массив состоит из элементов, у каждого есть ключ (=индекс) и значение. Ключи уникальны и не повторяются внутри одного массива.
- как, имея массив слогов и ключ одного слога, получить значение этого слога? Подсказка: использовать квадратные скобки. Может, в уроке это плохо описано, но конструкция вида массив[ключ] возвращает значение элемента с данным ключом. Здесь "ключ" может быть переменной, числом, строкой в кавычках, сложным выражением.
- далее, получая на каждом шаге цикла один слог, как их собрать в массив? Надо до цикла создать пустой массив, а в цикле добавлять в него еще один элемент. Добавление элемента в массив (внутри цикла) делается так: массив[] = значение; При этом ключ для нового элемента генерируется автоматически. Ну а после цикла ты уже можешь склеить собранные слоги из массива в одну строку.
То есть, ты плоховато знаешь работу с массивами и отсюда проблемы.
Давай после задачки про слоги решим дополнительную задачку, чтобы лучше в них разобраться. Дано 2 массива с оценками за январь и за февраль вида:
$january = [
'math' => 4,
'physics' => 5,
'literature' => 2
];
$february = [
'math' => 5,
'physics' => 5,
'literature' => 2
];
Напиши программу, которая выведет:
- по каким предметам оценки остались неизменными
- по каким улучшились
- по каким ухудшились
Выводиться данные должны сгруппированно, в таком виде:
Оценки не изменились: physics, literature
Оценки улучшились: math
Оценки ухудшились: (таких нет)
И еще вопрос по неймспейсам, если у меня например класс вью называется App\View\View , а шаблоны лежат например в App/templates, как лучше всего подключить шаблоны уровнем ниже(выше?) неймспейса? Я пытался как-то изворачиваться с двойными точками, но полное понимание так и не пришло.
На пхп второй день, хз че у него под капотом.
Получается в БД поле такого вида:
[
{"key": "Материал", "value": "металлический каркас"}, {"key": "Цвет подставки", "value": "черный"}
], а хотелось бы такого: [
{"Материал": "металлический каркас"}, {"Цвет подставки": "черный"}
].
Или вообще только массив, без объектов внутри, но теперь, так понимаю, json_array в Doctrine теперь deprecated.
Что можно придумать, чтобы при этом формы редактирования выводились в два поля: название характеристики и ее значение. Data Transformer? Вроде не то.
Пробовал через FormEvents::PRE_SUBMIT, тоже не вышло ключи изменить у коллекции. Возможно, это я неправильно делал.
На крайний случай можно через Event[Subcriber|Listener] Доктрины, но кажется, что это кривые костыли.
ебать ты монстра родил, вот моя регулярка, вродь норм отработала
$regexp = '/^ (\\+ 7|8)([ (-][0-9][ )-]){10}$/';
Я знаю что вп - это вордпресс причем он тут?
>оно на то и фатал еррор, чтобы останавливать программу
через try catch throwable не останавливает
Также, на regex101 https://regex101.com/r/qF7vT8/3 уже введены номера и можно простестировать свою регулярку. Помни что на этом сайте надо писать бекслеш один раз, например \s, а не \\s. Флаг m там стоит чтобы ^ и $ в регулярке обозначали «начало и конец любой строки», а не «начало и конец всего текста». Флаг g (его нет в PHP, он только на этом сайте) значит что надо искать все совпадения с регуляркой, а не только первое.
Там в уроке все написано, внимательнее будь
использую симфони4+доктрину. хочу чтобы доктрина сама обновляла created_at и updated_at для полей. такая возможность была раньше в бандле расширений доктрины https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/doc/timestampable.md
там именно так как я хотел - в аннотации указываешь по какому событию обновлять дату и не паришься. но проблема в том, что оно работает только для симфони2.
есть какое-то более актуальное расширение? понятно, можно вручную добавлять, но вдруг кто-то уже запилил готовое.
Нашел эту самую БД, да там что то есть и наверно то что нужно. Но там очень много всего и чот очень сложно. Ладно спасибо все равно.
>можешь положить все кнопочки в форму в которой у тебя прописан action='твой скрипт'
>Можно с помощью жквери. Типа присваиваешь функцию кнопочке, а в функции у тебя аякс.
Можешь пожалуйста пример привести?
1) Построчно прогоняя массив через форыч вносить в базу каждый раз используя INSERT:
INSERT INTRO <название таблицы> SET <имя столбца1> = <значение1>, <имя столбца2> = <значение2>...
2) Или же сформировать один большой запрос как делается при SQL дампе и использовать INSERT всего 1 раз:
INSERT INTRO <название таблицы> (`имя столбца1`,`имя столбца2`,...) VALUES ('значение11', 'значение12'...), ('значение21', 'значение22'...), ('значение31', 'значение32'...),...
>А может ты тогда напишешь код (внутри цикла) на русском и на PHP
Взять случайный элемент из массива и добавить к имеющемуся слову:
$name = $name . $letters[rand(0, 15)];
1)
<form method="post" action="имяскрипта.пхп">
<button type=submit>
</form>
2) <button onclick="ajaxfunction">
на 10000 строках не будет особо различий.Сделай обоими способами и измерь время
Обля, еще проще. Есть готовая функция, возвращающая случайный элемент массива:
$name = $name . array_rand($letters);
Сокращенный синтаксис конкатенации строк опускаю. Новичку проще так.
Один большой запрос всегда быстрее, чем много мелких. Однако, у БД есть ограничение на размер запроса, поэтому возможно потребуется разбить его на несколько множественных инсертов. Заметим, что при импорте дампа отключают для ускорения отключают проверку foreign key и удаляют индексы:
SET FOREIGN_KEY_CHECKS=0;
ALTER TABLE mytable DROP INDEX myidx;
По окончании импорта эти параметры восстанавливают.
([-)( 8]...
круглые скобки получают приоритет перед квадратными. эскейпи их
([-\)\( 8]...
Пагинация относится исключительно к представлению. Класс, в котором метод печатает ссылки на экран, не должен находится в модели. Только в представлении. Контроллер должен запрашивать у модели данные с двумя параметрами: $number_of_results, $skip_results, где первое - количество результатов на страницу. А второе = $number_of_results х $номер_страницы
>Альтернативой будет сделать цикл в отдельном шаблоне, и передавать туда объект, а потом еще и написать тыщу геттеров для полей класса
Цикл в шаблоне - это нормально, если оформлен по канонам
<?php foreach (...) : ?>
хтмл хтмл <?= $viewObject->joba->getNum(); ?>хтмл хтмл
<?php endforeach; ?>
не шарю в doctrine, но автоматическое обновление полей с датой - это функция БД. Для этого у поля типа timestamp прописывается дефолтное значение CURRENT_TIMESTAMP.
В php по умолчанию всегда неявным образом передает в функцию ссылку на параметр. Переменная создается в памяти только, когда ты внутри функции начинаешь её менять.
Да, цикл в шаблоне не представляет никаких проблем в стилистическом плане и модели MVC не противоречит
это я напиздел. с 4 все работает нормально, вот: https://packagist.org/packages/stof/doctrine-extensions-bundle
щас буду ебаться с настройкой
>>20368
1. у меня не мускул.
2. это можно делать где угодно (в принципе), но если ты используешь такую жирную абстракцию как ОРМ, то логично всю работу с БД делегировать ей. а как она там технически будет добавлять - мне пока неважно. возможно, она это делает по-разному в зависимости от БД.
Возможно, дефолтное значение поля БД должно быть прописано в твоей XML схеме, которую доктрина использовала для генерации БД и классов.
Повторюсь. Можно ли свой проект вместо студентов делать? ОП будет помогать тогда? Хочу сделать порезанную версию Anki, что бы дни для spaced repetition считались, а то руками в календаре отмечать я утомился.
да нет, вот пример:
/
@var \DateTime $created
@Gedmo\Timestampable(on="create")
@ORM\Column(type="datetime")
/
private $created;
/
@var \DateTime $contentChanged
@ORM\Column(type="datetime", nullable=true)
@Gedmo\Timestampable(on="change", field={"title", "body"})
/
private $contentChanged;
очень удобно.
короче настроил всю хуйню тупо по инструкции https://symfony.com/doc/master/bundles/StofDoctrineExtensionsBundle/index.html
если кому надо, подскажу
>@Gedmo\Timestampable(on="create")
>@Gedmo\Timestampable(on="change", field={"title", "body"})
О чем я и говорил. Это функция БД, которую ты включил с схеме базы.
Нет, не все так просто. Если бы это делала БД, то после сохранения сущности с такими полями нам надо было бы делать дополнительный запрос на загрузку сгенерированных дат. Потому лучше не гадать, а посмотреть исходник:
- https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/lib/Gedmo/Timestampable/TimestampableListener.php
- https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/lib/Gedmo/AbstractTrackingListener.php
- https://github.com/Atlantic18/DoctrineExtensions/blob/v2.4.x/lib/Gedmo/Timestampable/Mapping/Event/Adapter/ORM.php
Судя по коду, генерируется это в событиях onFlush и prePersist.
Где можно аджакс, сикуэл и прочие пхп поднять.
Устанавливал месяца 2 назад, но название забыл.
Можно ссылку на тутор, где показано как это все связать с обычным хтмл? (Хочу использовать бутстрап).
А я вот ещё не понимаю одной вещи.
Есть у меня какой-то условный index.html и script.php.
Привязываю я скрипт к кнопке в индексе.
Как он будет работать?
Индекс то я могу и в хроме посмотреть, а вот пхп?
Нужно запускать какой-нибудь сервер, чтоб все заработало?
правильно мыслишь
Бля, PDO - это прослойка между скриптом пхп и базой данных. Системы управления базами данных это Oracle, MSSQL, MySQL, PostgreSQL - это программы на подобие Excel, только текстовые. Они все управляются одним языком SQL. И если ты хочешь освоить базы данных, то тебе нужно освоить этот язык.
у меня короче есть две сущности: Article и Tag. у них будет bidirectional связь manyToMany (у многих статей может быть много тегов, для каждой статьи хочется знать ее теги и наоборот).
я после прочтения мануала http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-bidirectional короч пишу такой (псевдо)код:
//Article.php
@ORM\Table(name="articles")
class Article
@ORM\ManyToMany(targetEntity="Tag", inversedBy="articles")
@ORM\JoinTable(name="articles_tags")
private $tags;
//Tag.php
@ORM\Table(name="tags")
class Tag
@ORM\ManyToMany(targetEntity="Article", mappedBy="tags")
private $articles;
то есть по логике мануала должна создаться промежуточная таблица articles_tags (указана в аннотации JoinTable) и там должны быть два поля с айдишками статью и тега, которые будут образовывать составной первичный ключ. вроде заебись все.
далее делаю php bin/console doctrine:migrations:diff, создается файл миграции, но там ДВЕ промежуточные таблицы:
$this->addSql('CREATE TABLE articles_tags (article_id INT NOT NULL, tag_id INT NOT NULL, PRIMARY KEY(article_id, tag_id))'); // эта моя
$this->addSql('CREATE TABLE tag_article (tag_id INT NOT NULL, article_id INT NOT NULL, PRIMARY KEY(tag_id, article_id))'); // эта такая же, но автоматически сгенерированная
как так-то? почему их две? как сделать так, чтобы создавалась и использовалась только та, которую я указал?
у меня короче есть две сущности: Article и Tag. у них будет bidirectional связь manyToMany (у многих статей может быть много тегов, для каждой статьи хочется знать ее теги и наоборот).
я после прочтения мануала http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-bidirectional короч пишу такой (псевдо)код:
//Article.php
@ORM\Table(name="articles")
class Article
@ORM\ManyToMany(targetEntity="Tag", inversedBy="articles")
@ORM\JoinTable(name="articles_tags")
private $tags;
//Tag.php
@ORM\Table(name="tags")
class Tag
@ORM\ManyToMany(targetEntity="Article", mappedBy="tags")
private $articles;
то есть по логике мануала должна создаться промежуточная таблица articles_tags (указана в аннотации JoinTable) и там должны быть два поля с айдишками статью и тега, которые будут образовывать составной первичный ключ. вроде заебись все.
далее делаю php bin/console doctrine:migrations:diff, создается файл миграции, но там ДВЕ промежуточные таблицы:
$this->addSql('CREATE TABLE articles_tags (article_id INT NOT NULL, tag_id INT NOT NULL, PRIMARY KEY(article_id, tag_id))'); // эта моя
$this->addSql('CREATE TABLE tag_article (tag_id INT NOT NULL, article_id INT NOT NULL, PRIMARY KEY(tag_id, article_id))'); // эта такая же, но автоматически сгенерированная
как так-то? почему их две? как сделать так, чтобы создавалась и использовалась только та, которую я указал?
нашел свой косяк лол. я оказывается в обоих сущностях писал inversedBy, а надо в одной писать mappedBy.
как и везде, на начальном уровне несложная. пдо - это не только про БД, как правильно сказали, сначала надо освоить азы sql, уметь создавать таблицы, выбирать-добавлять-изменять-удалять данные через консоль. пдо - это встроенная библиотека пхп, предоставляющая несколько классов для работы с БД и предполагающая, что ты будешь использовать определенный подход при работе с ней
Почему-то не работает пример из урока, который должен был посчитать сумму двух чисел. Браузер выводит просто пустую страницу. Хотя hello world из прошлого примера срабатывает нормально.
Подскажите пожалуйста,что я делаю не так?
укажи в начале страницы (до хедера)
error_reporting(E_ALL);
ini_set("display_errors", 1);
и посмотри, что выводится. по коду должно все ок быть
Вот для таких случаев и придуман дебаггер. Прямо построчно выполняет программу и после каждого шага ты можешь посмотреть значения любой переменной.
Трейсы позволяют найти, какие функции в коде дольше всего выполнялись, найти проблемные места, из-за которых страница долго рендерится. Вроде в платных IDE есть просмотр трейсов, но хочется бесплатный инструмент.
Трейсы - это не то же, что результат профайлинга. Это именно последовательность вызовов всех функций в коде. Трейсы с реальных сайтов обычно весят десятки или сотни мегабайт, что добавляет интереса. Сами понимаете, расковырять такой лог вручную нереально.
Если есть заинтересованные люди, через пару-другую недель я распишу задачу подробнее.
Есть такой проект: https://habrahabr.ru/post/242275/ - но он вроде не показывает время и вообще, это не то.
Есть такой: https://github.com/tungnguyenson/xdebug-trace-explorer
Есть такой: https://github.com/corretge/xdebug-trace-gui
Есть такой: https://www.splitbrain.org/blog/2016-02/27-visualizing_xdebug_traces - это очень отдаленно напоминает то, что хотелось бы увидеть.
Есть такой http://thomashamba.ch/xdebug-trace-file-parser.html
Есть вопрос на SO: https://stackoverflow.com/questions/1456395/xdebug-trace-gui
Было бы неплохо этот прекрасный интерфейс задействовать или сделать аналогичный.
Чем ты трейсы просматриваешь/просматривал бы при условии что они начинаются с несколько десятков Мб и соответственно сотен тысяч вызовов?
Ну тот же екселевский файлик на гиг ты же парсишь как-то. В чём тут сложности?
Анон, подскажи, как запилить передачу даты из формы?
У меня затуп, как правильно передать GET.
http://php.net/manual/ru/
у жс нормальный мануал.
Есть ячейка <td></td> произвольной ширины.
Внутри должен быть <input></input> и <button></button>.
Кнопка строго 23х23 пикселя, прижата вправо. А инпут должен быть резиновым, занимая всё оставшееся место ячейки.
Вроде простая задача, но я не осилил.
Шаманю. Результат - либо фиксированная ширина инпута, либо элементы выходят за пределы ячейки и всю таблицу разносит к хренам.
Чтобы не было фиксированной нужно задавать не в пикселях значения. Залей пример кода на пастебин или ещё куда
Вроде нормально сделал, но INSERT не проходит.
https://ideone.com/EYyhPq
Что-то типа такого: https://jsfiddle.net/dj03n8sj/
Только там вообще даже в одну строку всё не умещается. У мен уже голова квадратная, с утра получше сделаю.
Первую задачу где?
>>20282
>Я много слышал про разделение логики приложения и логики представления, но с пагинацией я немного запутался, есть класс, в одном из методов которого я просто через цикл печатаю ссылки на экран, а потом объект пагинации передаю во вью, так нормально делать?
Не совсем, ты должен передавать в шаблон переменные с результатом, и уже в нём (шаблоне) выводить циклом
Например
for ($i = 0; $i < $pageCount; $i++) {
<a ...>$i</a>
}
>И еще вопрос по неймспейсам, если у меня например класс вью называется App\View\View , а шаблоны лежат например в App/templates, как лучше всего подключить шаблоны уровнем ниже(выше?) неймспейса? Я пытался как-то изворачиваться с двойными точками, но полное понимание так и не пришло.
__DIR__ . '/../level/up/path'
Вообще, обычно, папка с шаблонам находятся снаружи снаружи папки приложения
Не пиши на венде локалхост. Это так, к слову.
По поводу кода: мы тут не обязаны угадывать "у миня там ни праходит ряяя". Пиши четко, какая ошибка. Если пусто ,как у тебя в голове, въеби PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION и оберни скрипт в try—catch, опять же скажешь ошибку сюда, ну пшёл бля нах быстра!
Сука уже подумал что это мой скрин. Сталкнулся с точно таким же говном и тоже номера телефонов ебашил. В бэкслеше броблема
А как писать если не локалхост? Работает же.
А в коде, в 13 строчке $dbh->execute([NULL,$task,0,$taskDate]) or die ("Problems adding!"); срабатывает or die ("Problems adding!").
Тебе надо включить режим выброса исключений в PDO, иначе ты не увидишь сообщение об ошибке. передать этот параметр можно через конструктор или как в коде тут:
http://php.net/manual/ru/pdo.error-handling.php
Ставить try/catch не требуется. Просто включи у себя display_errors= 1 в php.ini и ошибка будет выведена на экран. Если проблема на хостинге, то на экран может и не вывестись, смотри тогда логи ошибок.
По крайней мере у меня, по крайней мере на семерке локалхост в майэскуэл работает намного медленнее 127.0.0.1 , попробуй поменять? На хрюше было норм, десятку нахуй родили непонятно.
Экзекьют возвра... ты читал доки а?? Не маневрируй — это тебе не поможет! Ошибку давай сюда але.
Форму правильней передать POSTом. Для этого в теге <form .... method=POST>
Параметры в скрипте будут доступны в массивах $_POST и $_REQUEST
Метод зависит от вида формы.
GET - для форм, не изменяющих состояние сервера, с небольшим объемом данных, и чтобы можно было поделиться/сохранить ссылку на результат (например: поиск, сортировка, переход к странице)
POST - для форм, меняющих состояние сервера, для форм с закачкой файлов, для больших объемов данных. Ссылкой поделиться нельзя, при обновлении страницы выскочит предупреждение.
>New google search design
https://ideone.com/ZSKmtw
Что я делаю не так и как отлаживать такие моменты?
50 строка, если что.
>>20998
Мне говорили, что с ВЕБ формы все уходит строкой и передается только get-ом.
>>20880
https://ideone.com/cNjfkw
У меня какая-то хуйня в массив попадает.
Сорре, в глаза долблюсь, не увидел ideone.
Костыль.
При юзанье этого кода https://ideone.com/ZTztnt получается такой результат: -----12------13array(3) { [0]=> string(0) "" [1]=> string(2) "12" [2]=> string(2) "13" } 1213
Ты выбрал нелучшее место для php кода. Если пхп покажет warning, то этот текст попадет в код твоей страницы между head и body. Броузер интерпретирует этот текст как начало body, а реальный боди будет игнорировать.
Но варнингов не было и отображается всё нормально кроме hover.
Воть - http://just4lulz.tk/oop.php
Это точно так задумано что в качестве разделителя строки на массив выступает комбинация 0- ?
Я искал любые меры, чтобы выбросить нуль, который забирается в первый индекс массива.
[0]=> string(0) ""
Я попробовал все 4, но проблема в самом регулярном выражении.
>Мне говорили, что с ВЕБ формы все уходит строкой и передается только get-ом.
задумайся о круге своего общения лол
силекс все
>>21233
>И как тогда правильно передавать значения с формы в пхп-скрипт?
смотря какие значения. особенность гета в том, что его параметры можно сохранить как ссылку и добавить в закладки, отправить другу и т.д. поэтому его используют в основном для путей. все остальное идет в пост, т.к. он во-первых защищает переданные данные при наличии https-соединения, а во-вторых, там нет ограничения на размер передаваемых данных.
также тебе никто не мешает передавать пост-запрос вместе с гет-параметрами (просто подставляя их в УРЛ). тогда и в $_POST, и в $_GET прилетят данные. подробнее (в комментах хорошее пояснение про неадекватность названия массива $_GET):
http://grokbase.com/t/php/php-general/112ckcxw97/using-both-get-and-post-in-the-same-page
// ==UserScript==
// @name 2
// @author 1
// @match https://vk.com/audio*
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js
// ==/UserScript==
var a = $('#delete').click();
location.reload();
Я кидал его в tampermonkey и все работало. А сейчас не получается. Подскажите, что можно сделать?
Мне не нужны закладки, но у меня была проблема в том, что через форму поступает тип данные не "дата", а строка.
Пришлось даже массивом разбивать и собирать заново, чтобы привести к формату, который требуется.
Блин, точно, флекс. Спасибо.
>>20888
Не знал, что такое есть. Ведёт себя немного по другому, но тоже подходит.
Ещё вопрос по бутстрапу. Какой путь кастомизации бутстрапа в Yii2 наиболее фен-шуйный? Мне нужно убрать padding у ячеек таблицы. В tables.less написано padding: @table-cell-padding;, а сам этот параметр прописан в variables.less. Но его изменение ничего не даёт. Гугл заводит то в перекомпиляцию бутстрапа, требующую NodeJS и ещё чего-то, то в принудительное отключение бутстрапа из зависимостей Yii и ручное подключение бутстрапа, сгенерированного с нужными параметрами на https://getbootstrap.com/docs/3.3/customize
Как это вообще делается правильно?
у тебя по-моему нет понимания что за что отвечает. в пхп и нет такого типа "дата". это может быть ты имешь в виду тип поля в html, он не имеет никакого отношения к типу данных, который есть в ЯП.
для пхп (и для других языков) "дата" - это циферки, которыми он манипулирует с помощью функций и классов, описанных у ОПа в уроке
https://github.com/codedokode/pasta/blob/master/php/datetime.md
или озвучь вопрос более конкретно.
Раньше лепили float ко всему где только можно, теперь flex и grid. У ячейки таблицы есть свой display, а менять его на flex? А нужна ли тогда таблица вообще? Таблица — для вывода табличных данных. Да, понятно что соблазнительно воспользоваться ей для автоматического выранивания сеточки, но мне лично кажется это неправильным.
Да, при желании содержимым ячейки можно поставить span или div c флексбоксом, внутрь которого запихнуть хоть анус Девы Марии, так чего бы весь сайт не засунуть туда а не только инпут с кнопкой?
>кастомизации бутстрапа
А какие варианты есть?
1) В своем стиле переопределить селекторы и подрубить его поверх.
2)
>ручное подключение бутстрапа, сгенерированного с нужными параметрами
Это когда уже определился со стилями, на финалочку.
>Have an existing configuration? Upload your config.json to import it.
Может быть, у тебя уже есть основное, загрузи и подредактируй что нужно.
3)
>Но его изменение ничего не даёт
Ну как бы ты не должен лезть в папку vendor, если я тебя правильно понимаю. Все изменения должны накатываться в твоем приложении.
А если я неправильно понимаю, может быть ты что-то неправильно сделал, поэтому оно не отобразилось.
Окей, тогда опишу целиком систему:
Пользователь вводит дату через форму HTML с type="date"
Дату нужно привести к определенному формату.
После этого, она вставляется в ссылку.
Я кликаю по ссылке и перехожу на сайт, который хавает геты и выдает мне нужное окно.
Как я это сделал:
https://ideone.com/nVbAXT
>В своем стиле переопределить селекторы и подрубить его поверх.
Не плучается. Подключаю css, в нём стили для td (к примеру). border почему-то удаётся изменить, а padding и margin нет, как будто они не учитываются вообще. Не понимаю, почему так происходит.
>Это когда уже определился со стилями, на финалочку.
Тоже не совсем понятно. Просто сгенерировать bootstrap на сайте и заменить им потороха папки vendor\bower\bootstrap ? Или отключить дефолтный бутстрап и рядом положить сгенерированный, подключив его в Ассетс?
>Не плучается
Твой стиль подключаешь последним в списке? Может фреймворк где-то после тебя сует стили, а ты не видишь.
Если уверен что ты папа:
Тогда открывай инструменты разработчика и смотри:
а) код самой готовой страницы, какие стили идут за какими, убедись все-таки, что ты последний
б) уже скомпилированные значения. Смотри всю историю, кто где padding-и на td менял. (инспектировать элемент)
Бутстрап с помощью js может тебе нагадить уже после загрузки страницы.
Еще раз: ты не должен лезть в вендор! Эти вещи писал не ты, и не тебе их редактировать. Раз ты используешь bower, там должно быть что-то наподобие нашего composer-овского конфига, вот в нем ты можешь переписать пути на папку assets (ну или как там это в твоем фреймворке делается вообще ;))
почему такие странные названия переменных? зачем массив - str_replace же есть?
+ валидация где?
я бы так сделал:
$userDate = array_key_exists($_GET['from']) ? strval($_GET['from']) : '';
if (!preg_match('~^(19|20)\d\d[-](0[1-9]|1[012])[-](0[1-9]|[12][0-9]|3[01])$~', $userDate)) {
throw new InvalidArgumentException('Incorrect data format'); // можешь на die() заменить
}
$date = str_replace('-', '/', $userDate);
Ему надо поменять местами в дате год месяц число (отформатировать как требует сторонний ресурс).
$names = ['Helen', 'Mike', 'Alice', 'Lena', 'Ana', 'Max', 'Bob'];
$rates = [1, 4, 5, 3, 8, 9, 10];
Можно ли c помощью какой-нибудь команды сделать значения массива $names индексами массива $rates?
Или по любому придется назначать индексы вручную?Как-то не очень удобно.
Большое спасибо
Превращаю все варнинги в эксепшены.
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
Пишу такой код:
try {
$content = file_get_contents($url, false, stream_context_create($request_headers));
} catch (ErrorException $e) { // обрабатываю }
Без превращения варнингов в эксепшены переменная $content всегда определена.
А, сука, если превращать - то при эксепшене undefined variable, сука! Да как так-то?! А как мне вытянуть значение функции, если там незначительный нотис выскочил (а при этом нотисы я хочу тоже кидать исключениями)? На самом деле ясно как - надо писать воркараунд в exception_error_handler для конкретного, сука, варнинга, и не кидать на него исключение.
Это же пиздец. Кто это проектировал?! Почему нельзя запустить exception_error_handler после того, как строка отработала, а не во время работы функции! Процедурный код же не рассчитан на такое поведение, он рассчитан, что он срет ошибками и при этом невозбранно возвращает значение! Ааааааааааааа
Вот что мне делать, если я хочу получать $content и при этом кидать эксепшены? Хуячить собаку на file_get_contents, затем чекать error_get_last()? А как я узнаю, что это ошибка именно с предыдущей строки?
>>1117974
>>18558
Я там обновил комментарии к задаче, посмотри, может что нового прочтешь.
> https://github.com/moabit/student-list/blob/master/composer.json#L5
> "fzaninotto/faker":"^1.7.1"
Это лучше было бы прописать в require-dev, то есть в зависимости для разработки. На продакшене ведь faker не требуется.
> https://github.com/moabit/student-list/blob/master/config.json
Этот файл используется в git и тут есть проблема: если разработчик склонирует твой проект и пропишет какие-то настройки, то он может закоммитить назад в проект измененный файл. Решение я описал в уроке: https://github.com/codedokode/pasta/blob/master/student-list.md#Скрытие-файлов-из-репозитория
> https://github.com/moabit/student-list/blob/master/public/index.php
> ini_set('display_errors', 1);
Это лучше прописывать в php.ini, а то не хочется, чтобы на продакшене ошибки выводились. Можно конечно прописать настройку в конфиге, но непонятно зачем дублировать функционал php.ini.
> https://github.com/moabit/student-list/blob/master/app/container.php#L20
> SET NAMES utf8mb4,
Вроде в PDO сделали опцию charset в конструкторе или в DSN.
https://github.com/moabit/student-list/blob/master/app/container.php#L35
> $container['pager'] = function ($c) {
Это не имеет смысла, так как у Pager есть конструктор. Также, ты по идее должен не переиспользовать один экземпляр Pager, а создавать каждый раз новый.
Также, мне кажется, в контейнере не стоит хранить классы с состоянием вроде Authorisation, а стоит создавать новую копию при каждом обращении. Представь, что мы обрабатываем 2 HTTP-запроса подряд. Первый запрос изменит состояние авторизации, и оно может повлиять на выполнение второго запроса.
> throw new RouterException('Неправильный путь');
надо назвать класс лучше, так как этот класс генерирует 404 и должен использоваться только в таких ситуациях, когда надо отдать 404. Например, RouteNotFoundException или Http404Exception.
> https://github.com/moabit/student-list/blob/master/app/Controllers/Controller.php#L18
> protected $view;
Эту переменную наверно лучше назвать twig
https://github.com/moabit/student-list/blob/master/app/Controllers/Controller.php#L37
Может, тут лучше было сделать абстрактную функцию index?
https://github.com/moabit/student-list/blob/master/app/Controllers/Controller.php#L42
> protected function getUserData()
Не очень понятно назначение метода. Он точно должен быть в каждом контроллере?
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php
здесь наверно лучше было бы сделать все же общую функцию для редактирования/регистрации, чтобы не передавать данные через поля. Такая передача данных затрудняет анализ логики кода.
> if (Util::checkCSRFToken() == false) {
Можно писать if (!Util::checkCSRFToken()), почитай про булевы значения.
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L60
> $this->c['authorisation']->signIn($token);
> $student->setToken($token);
вот тут есть тонкий момент. Что, если мы сгенерируем токен, поставим куку, а потом скрипт упадет, не записав данные в БД. Пользователь останется с кривым токеном. Это не проблема? Хотя, если сделать наоборот, может получиться, что мы создадим пользователя в БД, а куку не выдадим - будет еще хуже.
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L97
> $student->setName(ucfirst(trim(strval($_POST['name']))));
ucfirst не работает: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L93
> $student = new Student;
> if ($this->user) {
> $student->setID($this->user->getID());
> }
При обновлении данных лучше сделать так: загрузить студента из БД и затем обновить ему поля из POST. А то в твоем случае, если добавить какие-то новые поля, которые не редактируются через форму, но хранятся в БД и есть в объекте, то они могут потеряться при редактировании.
> private function editUser($token): void
Для $token можно поставить тайп-хинт
https://github.com/moabit/student-list/blob/master/app/Database/StudentDataGateway.php#L36
> if ($search != null) {
> $search = trim($search);
Если передать строку из одних пробелов, найдутся все студенты.
https://github.com/moabit/student-list/blob/master/app/Database/StudentDataGateway.php#L54
> @return array
> public function getStudents
лучше писать @return Student[] - это несет больше информации - смотри мануал https://docs.phpdoc.org/guides/types.html
> public function getStudents($orderField, $direction, $limit, $offset, $search = null):
Тайп-хинтов бы сюда завезти...
> throw new \PDOException('Неверный параметр сортировки');
В сообщение можно добавить значение ошибочных параметров для упрощения отладки.
Также, в коде маловато комментариев. Я бы советовал тебе взять за правило писать сначала комментарий к классу, а только потом сам класс.
https://github.com/moabit/student-list/blob/master/app/Helpers/Authorisation.php#L75
> return $this->isAuth;
тут не return null должно быть?
https://github.com/moabit/student-list/blob/master/app/Helpers/ErrorHandler.php#L33
> header("HTTP/1.0 404 Not Found");
> echo "Страница с таким адресом не существует";
без указания кодировки кириллица может не отобразиться. Добавь либо Content-Type либо тег meta charset. Также, на мобильных надпись будет выводиться очень мелко, можно добавить meta viewport.
https://github.com/moabit/student-list/blob/master/app/Helpers/Util.php#L27
> throw new ConfigException('Ошибка в файле конфигурации');
Стоит тут добавить текст JSON ошибки.
https://github.com/moabit/student-list/blob/master/app/Helpers/Util.php#L58
> $_COOKIE['CSRFToken'] != $_POST['CSRFToken']
Тут надо использовать строгое сравнение. Также, надо проверить случай, когда оба значения пусты.
https://github.com/moabit/student-list/blob/master/app/Validators/StudentValidator.php
Тайп-хинтов бы побольше.
https://github.com/moabit/student-list/blob/master/app/addStudents.php
Это лучше было наверно сделать в виде cli скрипта.
> $student->setSurname($faker->lastName.'а');
Faker не умеет в женские фамилии? Не хочешь исправить этот баг и законтрибутить исправление в Faker на благо всех? Сначала, конечно, надо повнимательнее изучить Faker, может там уже есть решение.
https://github.com/moabit/student-list/tree/master/app/views/templates
Может, стоит эту папку вынести на верхний уровень?
https://github.com/moabit/student-list/blob/master/app/views/templates/studentlist.twig
> {% if students is not empty %}
> много строк
> {% else %}
> <h4 class="text-center m-4 text-muted">По вашему запросу ничего не найдено</h4>
> {% endif %}
Лучше может быть короткий блок ставить сверху. Для читабельности.
> >{{ pager.search|e }}
В твиге автоэкранирование.
> {% elseif pager.notify=='registered' %}
Это как-то неправильно, что pager используется для хранения нотификаций, согласись? Это не его задача.
> <a href="?{{ pager.getSortingLink('name') }}"
Лучше возвращать ссылку уже с вопросом, а не собирать ее так по кускам.
Для twig надо бы включать strict_variables. Иначе он не скажет об отсутствующей переменной.
Вообще, код выглядит очень неплохо. Ты ведь наверно не начинающий? Может тогда автоматические тесты сделаешь? Урок есть: https://gist.github.com/codedokode/a455bde7d0748c0a351a
>>1117974
>>18558
Я там обновил комментарии к задаче, посмотри, может что нового прочтешь.
> https://github.com/moabit/student-list/blob/master/composer.json#L5
> "fzaninotto/faker":"^1.7.1"
Это лучше было бы прописать в require-dev, то есть в зависимости для разработки. На продакшене ведь faker не требуется.
> https://github.com/moabit/student-list/blob/master/config.json
Этот файл используется в git и тут есть проблема: если разработчик склонирует твой проект и пропишет какие-то настройки, то он может закоммитить назад в проект измененный файл. Решение я описал в уроке: https://github.com/codedokode/pasta/blob/master/student-list.md#Скрытие-файлов-из-репозитория
> https://github.com/moabit/student-list/blob/master/public/index.php
> ini_set('display_errors', 1);
Это лучше прописывать в php.ini, а то не хочется, чтобы на продакшене ошибки выводились. Можно конечно прописать настройку в конфиге, но непонятно зачем дублировать функционал php.ini.
> https://github.com/moabit/student-list/blob/master/app/container.php#L20
> SET NAMES utf8mb4,
Вроде в PDO сделали опцию charset в конструкторе или в DSN.
https://github.com/moabit/student-list/blob/master/app/container.php#L35
> $container['pager'] = function ($c) {
Это не имеет смысла, так как у Pager есть конструктор. Также, ты по идее должен не переиспользовать один экземпляр Pager, а создавать каждый раз новый.
Также, мне кажется, в контейнере не стоит хранить классы с состоянием вроде Authorisation, а стоит создавать новую копию при каждом обращении. Представь, что мы обрабатываем 2 HTTP-запроса подряд. Первый запрос изменит состояние авторизации, и оно может повлиять на выполнение второго запроса.
> throw new RouterException('Неправильный путь');
надо назвать класс лучше, так как этот класс генерирует 404 и должен использоваться только в таких ситуациях, когда надо отдать 404. Например, RouteNotFoundException или Http404Exception.
> https://github.com/moabit/student-list/blob/master/app/Controllers/Controller.php#L18
> protected $view;
Эту переменную наверно лучше назвать twig
https://github.com/moabit/student-list/blob/master/app/Controllers/Controller.php#L37
Может, тут лучше было сделать абстрактную функцию index?
https://github.com/moabit/student-list/blob/master/app/Controllers/Controller.php#L42
> protected function getUserData()
Не очень понятно назначение метода. Он точно должен быть в каждом контроллере?
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php
здесь наверно лучше было бы сделать все же общую функцию для редактирования/регистрации, чтобы не передавать данные через поля. Такая передача данных затрудняет анализ логики кода.
> if (Util::checkCSRFToken() == false) {
Можно писать if (!Util::checkCSRFToken()), почитай про булевы значения.
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L60
> $this->c['authorisation']->signIn($token);
> $student->setToken($token);
вот тут есть тонкий момент. Что, если мы сгенерируем токен, поставим куку, а потом скрипт упадет, не записав данные в БД. Пользователь останется с кривым токеном. Это не проблема? Хотя, если сделать наоборот, может получиться, что мы создадим пользователя в БД, а куку не выдадим - будет еще хуже.
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L97
> $student->setName(ucfirst(trim(strval($_POST['name']))));
ucfirst не работает: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
https://github.com/moabit/student-list/blob/master/app/Controllers/ProfileController.php#L93
> $student = new Student;
> if ($this->user) {
> $student->setID($this->user->getID());
> }
При обновлении данных лучше сделать так: загрузить студента из БД и затем обновить ему поля из POST. А то в твоем случае, если добавить какие-то новые поля, которые не редактируются через форму, но хранятся в БД и есть в объекте, то они могут потеряться при редактировании.
> private function editUser($token): void
Для $token можно поставить тайп-хинт
https://github.com/moabit/student-list/blob/master/app/Database/StudentDataGateway.php#L36
> if ($search != null) {
> $search = trim($search);
Если передать строку из одних пробелов, найдутся все студенты.
https://github.com/moabit/student-list/blob/master/app/Database/StudentDataGateway.php#L54
> @return array
> public function getStudents
лучше писать @return Student[] - это несет больше информации - смотри мануал https://docs.phpdoc.org/guides/types.html
> public function getStudents($orderField, $direction, $limit, $offset, $search = null):
Тайп-хинтов бы сюда завезти...
> throw new \PDOException('Неверный параметр сортировки');
В сообщение можно добавить значение ошибочных параметров для упрощения отладки.
Также, в коде маловато комментариев. Я бы советовал тебе взять за правило писать сначала комментарий к классу, а только потом сам класс.
https://github.com/moabit/student-list/blob/master/app/Helpers/Authorisation.php#L75
> return $this->isAuth;
тут не return null должно быть?
https://github.com/moabit/student-list/blob/master/app/Helpers/ErrorHandler.php#L33
> header("HTTP/1.0 404 Not Found");
> echo "Страница с таким адресом не существует";
без указания кодировки кириллица может не отобразиться. Добавь либо Content-Type либо тег meta charset. Также, на мобильных надпись будет выводиться очень мелко, можно добавить meta viewport.
https://github.com/moabit/student-list/blob/master/app/Helpers/Util.php#L27
> throw new ConfigException('Ошибка в файле конфигурации');
Стоит тут добавить текст JSON ошибки.
https://github.com/moabit/student-list/blob/master/app/Helpers/Util.php#L58
> $_COOKIE['CSRFToken'] != $_POST['CSRFToken']
Тут надо использовать строгое сравнение. Также, надо проверить случай, когда оба значения пусты.
https://github.com/moabit/student-list/blob/master/app/Validators/StudentValidator.php
Тайп-хинтов бы побольше.
https://github.com/moabit/student-list/blob/master/app/addStudents.php
Это лучше было наверно сделать в виде cli скрипта.
> $student->setSurname($faker->lastName.'а');
Faker не умеет в женские фамилии? Не хочешь исправить этот баг и законтрибутить исправление в Faker на благо всех? Сначала, конечно, надо повнимательнее изучить Faker, может там уже есть решение.
https://github.com/moabit/student-list/tree/master/app/views/templates
Может, стоит эту папку вынести на верхний уровень?
https://github.com/moabit/student-list/blob/master/app/views/templates/studentlist.twig
> {% if students is not empty %}
> много строк
> {% else %}
> <h4 class="text-center m-4 text-muted">По вашему запросу ничего не найдено</h4>
> {% endif %}
Лучше может быть короткий блок ставить сверху. Для читабельности.
> >{{ pager.search|e }}
В твиге автоэкранирование.
> {% elseif pager.notify=='registered' %}
Это как-то неправильно, что pager используется для хранения нотификаций, согласись? Это не его задача.
> <a href="?{{ pager.getSortingLink('name') }}"
Лучше возвращать ссылку уже с вопросом, а не собирать ее так по кускам.
Для twig надо бы включать strict_variables. Иначе он не скажет об отсутствующей переменной.
Вообще, код выглядит очень неплохо. Ты ведь наверно не начинающий? Может тогда автоматические тесты сделаешь? Урок есть: https://gist.github.com/codedokode/a455bde7d0748c0a351a
>почему такие странные названия переменных?
Это лишь часть кода.
>зачем массив - str_replace же есть?
Нужно поменять местами.
>+ валидация где?
На самом деле, переменные будут приходить от другого приложения и нужно просто запилить прослойку.
>$userDate = array_key_exists($_GET['from']) ? strval($_GET['from']) : '';
Сорян, такой код для меня сложен. Можешь объяснить?
>>21336
Т.е. это создаст переменную date из формата 'd/m/Y' и переменной strtotime($userDate) ?
>Сорян, такой код для меня сложен. Можешь объяснить?
мы не можем просто так взять из гета элемент массива, т.к. если этот параметр (from) не передадут, мы получим нотис от пхп undefined array index 'from'. чтобы этого не было, мы сначала должны убедиться, что элемент с таким ключом существует. мы это делаем внезапно функцией array_key_exists. strval нам приводит значение к типу "строка", как часть валидации опять же.
а тернарный оператор - это такой сахар для задания значения переменной в зависимости от условия. пример:
$foo = isset($bar) ? $bar : $somethingElse;
значит тоже самое, что
if ($isset($bar) {
$foo = $bar;
} else {
$foo = $somethingElse;
}
важно знать, что тернарный оператор - не замена if, то есть нельзя использовать его для реализации логики. только для задания значения переменной.
>Т.е. это создаст переменную date из формата 'd/m/Y' и переменной strtotime($userDate) ?
да
в том, что этот про пхп.
>>21464
https://github.com/symfony/demo не? по каким критериям хорошо оформленного?
>мы не можем просто так взять из гета элемент массива
Погоди.. что? Я просто написал $datefrom = date('d/m/Y', strtotime($_GET[from])); и все сработало.
>т.к. если этот параметр (from) не передадут
Я просто указал value="2018-01-01" . Я так понял, это костыль был?
Черт! Я только сейчас понял. У меня там ещё одно значение из get бралось и пустое значение дальше передавалось для обработки.
Чтобы этого избежать я написал:
if (empty($country)){
} else{
ну и дальше весь оставшийся код.
Нет, мне интересен пример хорошо оформленного проекта на битбакете, а не на гитхабе. У них раньше была ссылочка /explore, но сейчас она убрана, подозреваю, из-за того, что на нем мало публичных известных проектов.
ну я не знаю, какой у тебя код и поэтому говорю в общем случае.
если ты запросишь $_GET[blahblah], а его не передадут, то ты получишь php notice в процессе выполнения своего кода. поэтому данную ситуацию надо предусмотреть.
>if (empty($country)){
>} else{
тут два пути. если ты работаешь менеджером или в ТП, а тебя начальник загрузил какой-то временной задачей, то делай как работает и забей. а если ты планируешь дальше работать с пхп для себя или перекатиться, то имеет смысл изучить какой-то минимум основ. иначе будет постоянная боль и непонимание где сломалось, а каждая задача будет отнимать кучу времени.
>если ты запросишь $_GET[blahblah], а его не передадут, то ты получишь php notice в процессе выполнения своего кода. поэтому данную ситуацию надо предусмотреть.
Дай угадаю: если у меня там дальше SQL-запрос (сам скрипт для внутреннего пользования и можно не бояться инъекций), то у меня вылезет целая куча говна?
>если ты работаешь менеджером или в ТП,
Этот случай.
НО!
>а если ты планируешь дальше работать с пхп для себя или перекатиться
Посему, воспользуюсь тем, что написал ты.
По поводу это строчки:
$userDate = array_key_exists($_GET['from']) ? strval($_GET['from']) : '';
есть ощущение, что я что-то недопонимаю.
array_key_exists - это функция для проверки существует ли что-то в массиве.
1.Для переменных сгодится isset?
Вот так, например.
$userDate = isset($_GET['from']) ? strval($_GET['from']) : '';
2.А разве можно передать массив через форму?
strval - функция для превращения числа в строку. Как итог ты используешь логику "если есть что-то в массиве (у меня "в переменной"), то преврати полученное из гета в строку. в противном случае - пусть будет пустота.
> 2.А разве можно передать массив через форму?
Легко:
script.php?a[]=1&a[]=2
В скрипте сделай var_dump($_GET) и посмотри что в 'a'.
Мануал http://php.net/manual/ru/faq.html.php#faq.html.arrays
>А разве можно передать массив через форму?
Форма это и есть массив. У элементов формы есть name и value. И если не ошибаюсь, multiple select может прислать однотипный массив из всех выбранных option value.
$_POST("select") / ["option 1","option 2", ...]
Еще (поправьте меня если нет) можно через URL передать массив:
my.dot.com/?somearray=[eat,my,shorts]&somethingelse=1488
>strval - функция для превращения числа в строку
Не только числа, а всех типов. Приведение к строке (если это возможно). Можно даже объекты в строку превращать и массивы.
>в противном случае - пусть будет пустота
Вернется пустая строка. Именно строка! (пустая, да)
До кучи про тернарный:
(условие) ? (инструкция если условие вернуло true) : (инструкция если условие вернуло false)
Стопэ, посан! Т.е. все это время, когда я брал данные из формы, я брал их из ассоциативного массива?!
>вылезет целая куча говна?
она может не вылезти, если у тебя на продакшн-сервере не проставлено error_reporting E_ALL (а оно на проде не проставлено), но в любом случае надо это предусмотреть, т.к. на дев сервере обычно стоит максимально многословный вывод ошибок (если там не легаси) и намеренно генерировать нотисы - это говнокод.
>1.Для переменных сгодится isset?
для простых типов данных годится isset или !empty, в зависимости от того, что нужно (см таблицу сравнения типов в пхп https://secure.php.net/manual/en/types.comparisons.php)
для проверки наличия элемента массива принято использовать array_key_exists. в мануале написано почему https://secure.php.net/manual/ru/function.array-key-exists.php (смотри пример 2).
там некий комментатор писал, что иссет работает быстрее, но возможно в новых версиях пхп это уже не так.
>2.А разве можно передать массив через форму?
можно <input name="arrayname[item1]">
заменил его на https://symfony.com/doc/current/components/var_dumper.html
все ок заработало
error_reporting (-1);
mb_internal_encoding('utf-8');
$a = "Добра тебе \n Выпей чаю";
$b = mb_strlen($a);
echo $b;
Вот код из задачи, при исполнении в браузере выдает следущее
Fatal error: Uncaught Error: Call to undefined function mb_internal_encoding()
>вообще на php7 multibyte string работает
нет, блядь, решили удалить. она же нахуй никому не нужна.
какой смысл спрашивать то, что можно найти в гугле на первой строчке?
а, сорян, не увидел. ну php --ini напиши для начала. посмотри, должно быть что-то типа
Configuration File (php.ini) Path: /etc/php/7.2/cli
Loaded Configuration File: /etc/php/7.2/cli/php.ini
Scan for additional .ini files in: /etc/php/7.2/cli/conf.d
Additional .ini files parsed: /etc/php/7.2/cli/conf.d/10-mysqlnd.ini,
/etc/php/7.2/cli/conf.d/10-opcache.ini,
...
/etc/php/7.2/cli/conf.d/20-mbstring.ini,
если такой конфиг есть, посмотри php -m, выдаст установленные расширения
потом попробуй в cli запустить свой код (php -a) и если работает, скопируй конфиг в fpm или cgi, чем ты там пользуешься
Не, тут такая ситуация: у меня значение из гет передается в preg_split, чтобы разбить вводимую строку на значения.
Потом эти значения втупую скармливаются sql-запросу и далее, после переработки результата, запиливаются ссылки.
Configuration File (php.ini) Path: C:\WINDOWS
Loaded Configuration File: (none)
Scan for additional .ini files in: (none)
Additional .ini files parsed: (none)
>
>Configuration File (php.ini) Path: C:\WINDOWS
>Loaded Configuration File: (none)
>Scan for additional .ini files in: (no
хуита какая-то. на винде поставь опен сервер, там все из коробки работает
Нет. JS нахуй. Вот чистый HTML:
<form action="" method=GET>
<input name="yoba[1]" value="23">
<input name="yoba[2]" value="24">
</form>
В пхп скрипте будет доступно по
$_GET['yoba'][1]; // тут 23
$_GET['yoba'][2]; // тут 24
А на самом деле в форме индекс в скобочках можно не указывать. Тогда в скрипте будешь обходить массив
foreach ($_GET['yoba'] as $item) {
echo "$item \n";
}
Вывод:
22
23
Файл php.ini положи в одном месте - в директории с php.exe. В файле php.ini расскомменти строку, где подключается mbstring. Убедись, что эта библиотека присутствует у тебя на диске. В файле php.ini также должна быть правильно указана директория extensions. После всех изменений перезагрузи вебсервер.
Часть на шарпе я то напишу, но вот с пхп не знаю, что делать ;d
отправка ftp
Тебе нужен Apache а не php. Даже писать ничего не придется. Программа кидает, а он показывает сразу с датой закидки и его можно октрыть.
Нужно документацию читать, а не туториалы от васянов. В первых страницах документации есть объяснение, почему вариант с var_dump работать не будет.
>>21641
Читал обновления в уроке, мне кажется автор переборщил с выбором. Зачем новичку знать про Mercurial, когда от джуна почти 100% будут требовать Git? Зачем другие хостинги кода, если аккаунт на GitHub всё равно рано или поздно появится, ведь без него не создашь issue и не отправишь патч в популярную библиотеку. А тот же BitBucket лежит регулярно, у нас он на работе и я думаю склонять людей к GitLab после этого: https://www.theregister.co.uk/2018/01/10/bitbucket_outage/
Особенности работы с pg-функциями без PDO, ИМХО, стоит вынести в отдельный урок, уж слишком специфично, у новичка глаза разбегутся от обилия информации. Есть ещё такой анти-паттерн - soft coding, его можно применить не только к программированию: идея в том, что человек потерятеся, если дать ему слишком большой выбор. Хорошо, что выбор есть, но тут, как мне кажется, он только усложнит жизнь.
>>21560
https://habrahabr.ru/post/279291/
Мне кажется, что по дефолту добавлять это в CRA это не стоило. Тут до сих пор обсуждают целесообразность этого решения: https://github.com/facebookincubator/create-react-app/issues/2554
название файлов в php будут в массиве $_FILES, оттуда их можно переместить в нужную директорию.
>Нужно документацию читать, а не туториалы от васянов
о, профессионалы с ценными советами в треде
>Мне кажется, что по дефолту добавлять это в CRA это не стоило. Тут до сих пор обсуждают целесообразность этого решения: https://github.com/facebookincubator/create-react-app/issues/2554
чем это от обычного листенера ноды отличается?
Тем что листенер деды использовали, а это модное нововведение которое решает множество проблем (тоесть ничем).
https://repl.it/repls/NippyGraciousCrayfish
>Индеец стоит на бубнах
Апач стоит на базе данных
>над С
пропасть это С?
>перепутав голову с задом
очень сложно
Погодь, но sql-инъекция - это только вид взлома БД. Какое это может иметь отношение к багам?
Подожди, я не совсем понимаю твои действия.
То что ты описал - это же простое обращение к форме.
<input name="yoba[1]" value="23">
$_GET['yoba'][1]; // тут 23
<form action="" method="get">
<p><b>Введите название страны:</b><br>
<input type="text" name="country"></p>
$first= preg_split ($regexp, $_GET[country]);
-----------------------------------
Вопрос знатокам: а можно как-то в html-форме задать дате всегда актуальный день?
<p><b>Выберите дату:</b><br>
<input type="date" name="from" value="2018-01-01">
Пока что я вижу путь только через JS.
UPD.
Я перечитал твой пост 20 раз, заглянул в предыдущие и все понял.
Проще говоря, ты задаешь поля, как индексы массива, а он уже "собирается" в php скрипте.
Да, из-за своей невнимательности я запутался.
Короч, через форму мне нужно передать только отдельные значения, а не элементы массива. Тот вопрос был больше теоретическим.
Когда он в первый раз заходит - у него сохраняется костяк приложения (кешируется джаваскрипт, стили), но как быть с html страничками, они же не кешируются сами по себе?
Допустим я могу и темплейты страниц закешировать (в джаваскрипт).
Но как потом запустить этот джаваскрипт прямо во вкладке, когда нет доступа к сайту? Чтобы можно было работать и потом закоммитить изменения.
Этого я не понимат.
1. как вы расчитываете мощности? по наитию (тормозит - докупили) или какими-то инструментами/методиками?
2. насколько сильное значение для задержки имеет физическое расположение сервера? допустим, vps в амстердаме, а сайт русский. по идее задержка минимальная, но почему-то все используют русские vps для таких целей.
SELECT CHAR(113)+CHAR(107)+CHAR(113)+CHAR(107)+CHAR(113)+(SELECT (CASE WHEN (4622=4622) THEN CHAR(49) ELSE CHAR(48) END))+CHAR(113)+CHAR(107)+CHAR(107)+CHAR(106)+CHAR(113))
Да, это sql-инъекции, но какая их роль? В данном случае это просто текст 'qkqkq1qkkjq0', у меня залогированно несколько подобных запросов которые получают текст 'qkqkq1qkkjq0' разными запросами.
Посмотреть проходит ли инъекция и какая БД установлена. Скорее всего запросы спамит робот.
Там есть варианты (да, какие-то сервис-вокеры), но если ты почитаешь описание, то увидишь, что это самая кривая и неудачная архитектура из всех, что можно было придумать. Поэтому предлагаю не делать такой функционал. Если у клиента постоянно нет связи, для него лучше сделать оффлайн приложение.
Русские впс используют, потому что они дешевые (poiskvps). У хостеров часто можно попросить тестовый период и протестировать сайт под нагрузкой. Можно также предложить оплатить эти несколько дней. Также, можно читать отзывы.
Да, робот спамил, так как там порядка 5-6 запросов в секунду приходило. Я тоже подумал, что скорее всего проверка чисто на получение ошибки БД. Нагуглить похожих запросов не вышло и само слово вроде как рандомное, но тогда не ясно, зачем именно это слово впихивалось разными способами в запросы
Да но только в случае если у родительского класса конструктор не private метод, так как дочерний класс наследует все public/protected методы от своих родителей
Да. А если этот конструктор приватный/защищенный, то будет выдана ошибка. Такие конструкторы используют, чтобы запретить создание объекта через new снаружи класса.
> Ареал макак простирается от Афганистана до Юго-Восточной Азии, а также до Японии. Особенным разнообразием видов отличается остров Сулавеси, где проживают шесть эндемичных видов макак. Единственным представителем семейства, встречающимся за пределами Азии, является магот, живущий в Северной Африке и в Гибралтаре.
изящно, лол
>>22497
так это ж ПРОГРАММИРОВАНИЕ. профессия будущего.
если хочешь дешевле, ищи школьников, правда возможно потом будешь с ошпаренной жопой искать кого-нибудь, кто выправит их говнокод, и тебе 50 баксов в час покажутся выгодной сделкой. но ты видать предприниматель, поди любишь риск, азарт, адреналин
Cпасибо, опушка, за всё.
> Чтобы вывести ссылку, ты пишешь в шаблоне {{ path(...) }} . Вместо этого можно сделать класс UrlGenerator, в нем методы вроде getTestsByTagUrl(Tag $tag): string. И использовать их. Выгоды:
Я тебя правильно понял? https://github.com/TheSidSpears/test_hub/commit/48de6c290d05ca63a48a5aa7bf8fbf67fb67fb5f
>> По переменным окружения - не стоит ли добавить им уникальный префикс вроде TH_..., чтобы они были гарантированно уникальными?
> И тут тоже не понял, о каких переменных ты говоришь
Переменные окружения в env.dist - больше их вроде нигде нету.
В этом файле стандартные переменные APP_ENV и DATABASE_URL. Зачем их переименовывать и как их система прочтет? (в этом разобраться самому)
>У Симфони есть куцая статья https://symfony.com/doc/current/testing/database.html и первый вариант (mock entity manager) я не советую делать, это будут очень некачественные и хрупкие тесты
Нужно тестировать репозитории на копии основной БД? А как держать эту БД актуальной? Это ж нужно миграции и там и там проводить. Как-то не удобным это кажется
> Set number of failed attempts for instantly created item
> public function setFailedAttempts($failedAttempts)
Вот такого лучше избегать. Увеличивать число попыток в тесте лучше тем же способом, каким это будет делать приложение, а не делать костыли там, где без них легко обойтись.
> Более того, смотри, ты добавил метод setFailedAttempts для тестов, а затем еще и написал тест для него. Ты тесты ради тестов пишешь, получается? Так делать не надо, это просто трата времени. Тестировать надо тот код, который будет использовать приложение.
Нет, эти 2 ф-ии используются исключительно для заполнения Fixtures. Вот тут https://goo.gl/FB1ikp Собственно, я и тестирую, что они отрабатывают первый раз и больше не срабатывают
>> public function findByTag(Tag $tag){
> Вообще, Доктрина генерирует методы finxByXXX, findOneByXXX, они тут не подошли бы?
Я попытался разобраться https://drive.google.com/file/d/1Gvt38WwASpFcdFU3z9ZDuvrZ3pfaWbun/view?usp=sharing
Видимо, не подойдёт
> Я тут еще хотел посоветовать использовать faker в fixtures, но погуглил, и увидел, что он там уже используется (через alice), интересно. не знал про такую штуку. Ну прекрасно, если вдруг не знаком с ним, изучи faker, пригодится.
Ага, именно их я и использую. Правда до конца разобраться не могу, т.к. я учился на Alice 2, а уже давно существует 3-я версия, её я и поставил. Но в ней много чего поменялось. Долгое чтение документации и дебаг исходников результатов не дал. Позже вернусь к этому
https://github.com/TheSidSpears/test_hub/blob/master/templates/base.html.twig#L22
>> {% if isMainRoute is defined and isMainRoute == true %}
> Вот это мне не нравится. У тебя переменная может быть передана, а может не быть. Как писать надежный код в такой ситуации?
А как быть то? Передавать isMainRoute во всех контроллерах избыточно, а как-то определять, что "вид вызван из MainController" надо
https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/list.html.twig#L34
>Это костыли, нужна нормальная функция-хелпер для склонения чисел, а еще лучше сразу использовать синтаксис для переводимых (локализумых) строк, так как в разных языках правила выбора формы слов разные.
использовать синтаксис для переводимых строк? Это как?
>> public function tagList(Request $request, PaginatorInterface $paginator)
> Почему пагинатор передается в аргументы метода контроллера? Это такой DI?
Как я понял, нужно в конструкторе его определять?
> if ($form->isSubmitted() && $form->isValid()) {
> $searchString = $form->getData()['text'];
> } else {
> $searchString = $request->query->get('text');
> }
> А зачем else?
При переходе на следующую страницу, условие $form->isSubmitted() уже не выполняется, поэтому я беру $searchString из get-параметра
https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/by_tag_list.html.twig
Проверь, соответствует ли имя шаблона гайдлайнам Симфони (я сам не помню).
>Я такого не нашел. Но вот в исходниках имена разделяются нижним подчеркиванием
> Чтобы вывести ссылку, ты пишешь в шаблоне {{ path(...) }} . Вместо этого можно сделать класс UrlGenerator, в нем методы вроде getTestsByTagUrl(Tag $tag): string. И использовать их. Выгоды:
Я тебя правильно понял? https://github.com/TheSidSpears/test_hub/commit/48de6c290d05ca63a48a5aa7bf8fbf67fb67fb5f
>> По переменным окружения - не стоит ли добавить им уникальный префикс вроде TH_..., чтобы они были гарантированно уникальными?
> И тут тоже не понял, о каких переменных ты говоришь
Переменные окружения в env.dist - больше их вроде нигде нету.
В этом файле стандартные переменные APP_ENV и DATABASE_URL. Зачем их переименовывать и как их система прочтет? (в этом разобраться самому)
>У Симфони есть куцая статья https://symfony.com/doc/current/testing/database.html и первый вариант (mock entity manager) я не советую делать, это будут очень некачественные и хрупкие тесты
Нужно тестировать репозитории на копии основной БД? А как держать эту БД актуальной? Это ж нужно миграции и там и там проводить. Как-то не удобным это кажется
> Set number of failed attempts for instantly created item
> public function setFailedAttempts($failedAttempts)
Вот такого лучше избегать. Увеличивать число попыток в тесте лучше тем же способом, каким это будет делать приложение, а не делать костыли там, где без них легко обойтись.
> Более того, смотри, ты добавил метод setFailedAttempts для тестов, а затем еще и написал тест для него. Ты тесты ради тестов пишешь, получается? Так делать не надо, это просто трата времени. Тестировать надо тот код, который будет использовать приложение.
Нет, эти 2 ф-ии используются исключительно для заполнения Fixtures. Вот тут https://goo.gl/FB1ikp Собственно, я и тестирую, что они отрабатывают первый раз и больше не срабатывают
>> public function findByTag(Tag $tag){
> Вообще, Доктрина генерирует методы finxByXXX, findOneByXXX, они тут не подошли бы?
Я попытался разобраться https://drive.google.com/file/d/1Gvt38WwASpFcdFU3z9ZDuvrZ3pfaWbun/view?usp=sharing
Видимо, не подойдёт
> Я тут еще хотел посоветовать использовать faker в fixtures, но погуглил, и увидел, что он там уже используется (через alice), интересно. не знал про такую штуку. Ну прекрасно, если вдруг не знаком с ним, изучи faker, пригодится.
Ага, именно их я и использую. Правда до конца разобраться не могу, т.к. я учился на Alice 2, а уже давно существует 3-я версия, её я и поставил. Но в ней много чего поменялось. Долгое чтение документации и дебаг исходников результатов не дал. Позже вернусь к этому
https://github.com/TheSidSpears/test_hub/blob/master/templates/base.html.twig#L22
>> {% if isMainRoute is defined and isMainRoute == true %}
> Вот это мне не нравится. У тебя переменная может быть передана, а может не быть. Как писать надежный код в такой ситуации?
А как быть то? Передавать isMainRoute во всех контроллерах избыточно, а как-то определять, что "вид вызван из MainController" надо
https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/list.html.twig#L34
>Это костыли, нужна нормальная функция-хелпер для склонения чисел, а еще лучше сразу использовать синтаксис для переводимых (локализумых) строк, так как в разных языках правила выбора формы слов разные.
использовать синтаксис для переводимых строк? Это как?
>> public function tagList(Request $request, PaginatorInterface $paginator)
> Почему пагинатор передается в аргументы метода контроллера? Это такой DI?
Как я понял, нужно в конструкторе его определять?
> if ($form->isSubmitted() && $form->isValid()) {
> $searchString = $form->getData()['text'];
> } else {
> $searchString = $request->query->get('text');
> }
> А зачем else?
При переходе на следующую страницу, условие $form->isSubmitted() уже не выполняется, поэтому я беру $searchString из get-параметра
https://github.com/TheSidSpears/test_hub/blob/master/templates/tests/by_tag_list.html.twig
Проверь, соответствует ли имя шаблона гайдлайнам Симфони (я сам не помню).
>Я такого не нашел. Но вот в исходниках имена разделяются нижним подчеркиванием
Кстати, у меня тоже повышение. Спрыгнул с bitrix'а на symfony в другую компанию. Скоро выхожу, думаю, эти полгода-год будут насыщенными.
Спасибо ОПу!
>Спрыгнул с bitrix'а на symfony
Поздравляю, братишка. Привыкай к ООП-парадигме, и никогда не возвращайся в битрикс, ни за какие деньги, иначе умрёшь в душе как специалист
не представляю, как у тебя хватило сил работать с битриксом.
тот же стул но без пик
/var/
/vendor/
Кто-нибудь в курсе, как фиксить?
ОП, добра тебе, что посмотрел!
>вот тут есть тонкий момент. Что, если мы сгенерируем токен, поставим куку, а потом скрипт упадет, не записав данные в БД. Пользователь останется с кривым токеном. Это не проблема? Хотя, если сделать наоборот, может получиться, что мы создадим пользователя в БД, а куку не выдадим - будет еще хуже.
Я подумал, может лучше через транзакцию в бд добавление/редактирование студента сделать? Или после редиректа проверять куку, и если она кривая, то ее удалять?
>Faker не умеет в женские фамилии?
Фейкер умеет только в женское имя и ФИО. Метод lastName не примает параметр $gender как, например, метод для генерации ФИО. Можно было бы генерировать женское ФИО, и затем выдерать из строки имя и фамилию, но я подумал, что проще просто сделать фамилию и добавить 'а'.
Если в консоли сделать git status, он эти папки показывает? Если да, то гитигнор настроен неправильно, если нет, то проблема в phpstorm и стоит начать с гугления по словам phpstorm gitignore not working.
Что-то более классическое бы. Нет такого?
+ .gitignore
Во всяких гайдах добавление модели в базу выглядит вот так.
File::create(['name' => $filename,
'size' => $size,
'created_at' => $created_at,
'comment' => $comment]);
Класс файл наследует Illuminate\Database\Eloquent\Model
И вот я решил посмотреть что за метод такой create. В моделе Eloquent'a такого метода нет. Но есть функция
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
Я так понимаю что функция создает инстанс модели и запускает статический метод, как обычный. Но метода create нет в модели и нет в интерфейсах которые она реализует и нет в трейтах которые она наследует. Ну собственно вопрос что за метод такой и откуда он берется.
Но изучать все же симфони, уй, ларавел. Вкатывальшик => конкуренция => работа
>>22911
git status эти папки не показывает. Ща буду гуглить
>>22910
А зачем тебе самый простой? самый простой - это какой-нибудь недофреймворк 10-летней давности Учи самый полезный, например >>22912
ОП, ты советовал использовать роутинг в yaml файлах вместо аннотаций. Но я тут столкнулся с проблемой и покопался в доках. Есть такая магическая вещь, как @ParamConverter (https://symfony.com/doc/master/bundles/SensioFrameworkExtraBundle/annotations/converters.html)
Она определяет что в
/
@Route('/tests/tag/{name}')
/
public function testsByTag(Tag $tag){
...
}
{name} это $tag->getName()
И как я понял, это фишка аннотаций.
Получается при использовании yaml-роутинга нужно будет писать типа
public function testsByTag(string $name){
$tag = $tagRepository()->findByName($name);
...
}
По-моему, это только усложнения. Или есть еще варианты?
>>22911
git status эти папки не показывает. Ща буду гуглить
>>22910
А зачем тебе самый простой? самый простой - это какой-нибудь недофреймворк 10-летней давности Учи самый полезный, например >>22912
ОП, ты советовал использовать роутинг в yaml файлах вместо аннотаций. Но я тут столкнулся с проблемой и покопался в доках. Есть такая магическая вещь, как @ParamConverter (https://symfony.com/doc/master/bundles/SensioFrameworkExtraBundle/annotations/converters.html)
Она определяет что в
/
@Route('/tests/tag/{name}')
/
public function testsByTag(Tag $tag){
...
}
{name} это $tag->getName()
И как я понял, это фишка аннотаций.
Получается при использовании yaml-роутинга нужно будет писать типа
public function testsByTag(string $name){
$tag = $tagRepository()->findByName($name);
...
}
По-моему, это только усложнения. Или есть еще варианты?
> Я так понимаю что функция создает инстанс модели и запускает статический метод, как обычный.
__callStatic создаёт инстанс модели и обращается к нестатическому методу create. Этого метода в сущности нет, поэтому срабатывает __call: https://github.com/laravel/framework/blob/5.5/src/Illuminate/Database/Eloquent/Model.php#L1470
Там видно, что создаётся Builder (построитель запросов, метод newQuery) и уже у этого билдера вызывается метод create, который находится тут: https://github.com/laravel/framework/blob/5.5/src/Illuminate/Database/Eloquent/Builder.php#L750
Это очень специфичная для Laravel магия, не уверен, что тебе нужны эти кишки. И не знаю, что там у тебя за васян-гайд, но created_at самому ставить не нужно, он и так сгенерируется благодаря трейту HasTimestamps. Лучше почитай: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
зато точно можно сказать, что не в .gitignore проблема лол
Спасибо большое!
Опа мануалы прочитал уже все.
Просто хотелось использовать именно готовое решение. Изначально делал свой класс работы с бд.
там power saving mode есть, можешь попробовать. но вообще, если он тормозит даже когда все проиндексировал, это повод проапгрейдиться.
если ты тот анон, про которого я думаю, то у тебя паранойя: тебе мерещится, что все кругом читают "васян-туториалы", а один ты в мире знаешь о существовании мануала
Посоны, допустим на сайте вам нужно выбирать данные из базы для формирования странички. Допустим же, что для этого нужно больше, чем один или даже два запроса к базе. Вы что их последовательно делаете что ли? Или, всё-таки, параллельно? Если параллельно, то кто как это делает? Я пришёл к вам из питона и немного охуел что нет одного хорошего простого решения, которым бы все пользовались. Помогите понять и определиться.
Запросы делаются последовательно. Про параллельные запросы на пхп впервые слышу, хотя, наверное можно форкнуться в пхп и сделать их. Нормальная практика делать по 50-100 запросов на страничку. Кто крут в SQL может все данные достать за один запрос с подзапросами и хранимыми функциями.
>Нормальная практика делать по 50-100 запросов на страничку
shiiiiiii~
>Кто крут в SQL может все данные достать за один запрос с подзапросами и хранимыми функциями.
Это-то как раз несложно. Вот только потом обрабатывать это в контроллере ебанёшься.
Мда, видимо в пхп-мирке свои понятия нормальности. Придётся приспосабливаться. Хотя вот я нагуглил php-icicle и там есть вот такое
https://github.com/amphp/mysql
Т.е.: у меня есть две таблицы из базы данных. Нужно сделать из них многомерные массивы, а потом научить код их обрабатывать.
Как это можно сделать?
есть разные варианты, погугли по теме "асинхронный php" или "php pthreads". разные запросы К СКРИПТУ выполняются параллельно и так. если тебе требуется ускорять обращения к бд в рамках одного запроса к скрипту, то это наверное надо делать не распараллеливанием, а оптимизацией запроса.
другое дело, если у тебя один запрос выполняется 10 секунд, второй 10, они никак не зависят друг от друга и оба нужны для вывода данных, то можно заморочиться с асинхронностью или multithreading. но это история для каких-то внутрисерверных cli-ситуаций, а не для формирования страничек пользователям.
хорошо работая в одной и той же компании макакой ровно год и не получить повышения - надо быть дебичем
Этот прав, пришёл в компанию джуном-обосрышем с полугодичным опытом макакинга
Изучал где-то с 2012 по 2016. В 2017 переехал в дс и нашел работу. Всем спасибо. До миддла пока не повысили, но получаю довольно таки миддловскую зарплату судя по рынку
120к
300к в наносекунду
Сейчас набегут дебилы которые "Да я как только Hello World" написал сразу за 100к работу нашол. А потом получил опыт 7 дней и сразу синьюр помидор 300к релокейт релокейт в гугол. Я вот даже не знаю откуда столько желчи в людях.
>>23325
Пару лет как обучился у опа, нахватался всяких гайдов с интернета, даже 2 месячный курс купил по PHP. Но дальше фриланса так и не вкатился, причём получаю с него тыщ 15 в месяц(имею основную работу). Не ххватает уверенности в силах хоть убей. всё кажется что возьмусь сейчас за работу, а там 9000 подводных камней, подведу работодателя. Больше всего мешает то, что не знаю досконально Wordpress, laravell, а от симфони я вообще в обморок падаю. Столько то там наворотов.
Я наверное один такой неудачник.
Как правильно вызывать php-скрипты из html?
Вот есть у меня html страница и php скрипт, где я там должен прописать что-то типа execute main.php?
Или это как-то по другому работает?
Пол дня гуглил, но не могу понять такую базовую вещь.
Никак.
Ты что-то делаешь не так. PHP создан для того чтобы из него создавать HTML, а не наоборот.
В любом отображаемом месте хтмл страницы нужно прописать специальный тег
<?php echo "пхп рабоатет"; ?>
Не расстраивайся. Сидя в своей Мухосрани я даже фриланс за 15к не смог найти, поэтому пришлось рвануть в дс.
Тоже был дикий страх подвести, моментами в начале работы хотелось просто послать все, менеджеров, тестеров, всех.
И было такое, что поначалу сильно говнокодил.
В одной конторе даже сайт положил без восстановления XD. Но они и сами виноваты, там не было ни гита, ни других кодеров.
Свалил оттуда на следующий день, оформление не по ТК было.
Но ничего, вытянул, с вордпрессом немного помог удаленный кодер, который давно на нем сидит. Постепенно дали нормального лида, который ведет все переговоры по срокам и ТЗ и вообще сильно помогает. Помогает то, что многие чуваки в айти натурально сидят на бордах, т.е. с ними проще на одной волне быть.
Спасибо за стори анон, прямо мёд для моего сердца (или как-то так). Буду пытаться вкатываться. Всю жизнь мечтал быть программистом, да только в моём мухосранске платят больше не программистам. Буду дальше искать работу мечты.
>Я пришёл к вам из питона
Где вместо FastCGI используется WSGI, такой же синхронный интерфейс вебсервера.
В reference manual почитай array functions. Их много и под все нужды. Советую ограничиться двумерными массивами. Пхп очень много памяти на многомерные тратит, ему может не хватить, упрется в ограничение в настроке.
Мне вот просто интересно а параллельное выполнение вопроса, какую задачу решает? Ну так, просто чтобы в курсе быть.
29
На всякий случай. А то нашел небольшой баг у себя, при некорректном ответе внешнего API можно исказить URL для следующего запроса.
https://repl.it/@Uzas/WorthlessUnusualArthropods
>питоном
Тогда уж с С. Но на самом деле в php это тоже рабочий код.
fwrite - функция вывода в resource-первый-аргумент строки второго-аргемента
первый аргумент - константа стандартного потока-вывода STDOUT, второй - строка.
По сути так и работает под капотом echo или print. Я, например, люблю все эти fwrite, fputs, fgets и тп
Спасибо, успокоил, а вообще пойдет ли в плюс при трудоустройстве, что я в сфере ИТ работаю и образование инженера?
Ээ... ну как бы сокращение общего времени запросов к базе. Что быстрее:
- 10 последовательных запросов к базе
- 10 параллельных запросов к базе
В первом случае общее время запросов будет равно сложению времени каждого из них. Во втором - длине самого долгого запроса.
>>23531
Я про запросы к базе из скрипта. Допустим, у тебя есть контроллер, где ты вызываешь несколько методов, которые возвращают тебе из базы результат.
Будут на собесы приглашать чаще, чем вкатывальщика из другой области.
А на практике не поможет, будет столько же страгглинга на первых порах, как и у всех. Разве только если ты не пм какой, тогда тех процессы тебе понятней будут, но они и так не сложные.
\d{10}
Я разобрался, надо было сделать вот так.
https://primes.utm.edu/primes/home.php
Как видишь, для каждого пункта меню создана отдельная страница.
>Вот есть у меня html страница и php скрипт, где я там должен прописать
Переименуй файл с html страницей в .php и напиши в началит файла <?php include "script.php"; ?> имя и путь к скрипту свои.
На твой вопрос так просто не ответить. Это ведь зависит от конфигурации сервера. Обычно сервер настраивают так:
- если идет обращение к файлу с расширением .php, то выполнить код из него
- если идет обращение к файлу с другими расширениями, вроде .html, то просто отдать его клиенту
В этом случае описанное тобой никак не реализовать без изменения настроек сервера.
> где я там должен прописать что-то типа execute main.php?
Надо настроить сервер, чтобы он файлы html выполнял бы как PHP код. Как именно, зависит от используемого веб-сервера. Но я не очень понимаю, зачем и что тебе мешает назвать файл .php или использовать ЧПУ.
>>23605
>>23273
Ты в своем расчете кое-что не учел:
- одни запросы могут зависеть от других и их нельзя выполнить параллельно
- база данных обладает неограниченным резервом производительности и выполняет запрос за одно и то же время независимо от нагрузки
На практике, второй пункт может выполняться, если сервер мощный и посетителей немного, но в других случаях запросы могут начать выполняться медленнее, когда их много.
Также, чтобы использовать параллельные запросы, надо, как я понимаю, использовать асинхронное программирование, и это та еще боль. Надо переписывать код из последовательного скрипта в более сложную конструкцию. И как там с обработкой ошибок? В питоне невыполненные обещания умеют бросать исключения? Я не знаю, я имел дело только с промисами из JS и PHP, там они не умеют это.
Ну и я плохо представляю, как можно распараллелить ORM, с наличием там "ленивых" запросов. Это все функции в сущностях надо переделывать на асинхроонную модель.
Так что сомневаюсь, что это так просто и всегда оправданно.
Не забывай также, что программисты часто стремятся оптимизировать технические характеристики, как память или потребление CPU, но бизнесу еще может быть интересно, чтобы разработка шла быстро и не стоила как космический корабль. Параллельный код может быть дороже и сложнее.
Ну и ты еще исходишь из предположения, что запросы к БД это самая долгая часть выполнения скрипта. Я смотрел трейсы в PHP-приложениях, и могу сказать, что это далеко не всегда так. Оптимизированный запрос с индексами на хорошем сервере может выполняться меньше 1 мс. Нужно ли его распараллеливать?
На Питоне все SQL запросы выполняют параллельно? Теперь уже я удивлен, первый раз про такое слышу. Покажи-ка ссылочку.
Если тебе все равно хочется отправлять параллельные запросы, я бы начал с изучения фреймворка ReactPHP и поиска асинхронного драйвера для БД. По моему, mysqli что-то такое может уметь, но я не уверен.
На твой вопрос так просто не ответить. Это ведь зависит от конфигурации сервера. Обычно сервер настраивают так:
- если идет обращение к файлу с расширением .php, то выполнить код из него
- если идет обращение к файлу с другими расширениями, вроде .html, то просто отдать его клиенту
В этом случае описанное тобой никак не реализовать без изменения настроек сервера.
> где я там должен прописать что-то типа execute main.php?
Надо настроить сервер, чтобы он файлы html выполнял бы как PHP код. Как именно, зависит от используемого веб-сервера. Но я не очень понимаю, зачем и что тебе мешает назвать файл .php или использовать ЧПУ.
>>23605
>>23273
Ты в своем расчете кое-что не учел:
- одни запросы могут зависеть от других и их нельзя выполнить параллельно
- база данных обладает неограниченным резервом производительности и выполняет запрос за одно и то же время независимо от нагрузки
На практике, второй пункт может выполняться, если сервер мощный и посетителей немного, но в других случаях запросы могут начать выполняться медленнее, когда их много.
Также, чтобы использовать параллельные запросы, надо, как я понимаю, использовать асинхронное программирование, и это та еще боль. Надо переписывать код из последовательного скрипта в более сложную конструкцию. И как там с обработкой ошибок? В питоне невыполненные обещания умеют бросать исключения? Я не знаю, я имел дело только с промисами из JS и PHP, там они не умеют это.
Ну и я плохо представляю, как можно распараллелить ORM, с наличием там "ленивых" запросов. Это все функции в сущностях надо переделывать на асинхроонную модель.
Так что сомневаюсь, что это так просто и всегда оправданно.
Не забывай также, что программисты часто стремятся оптимизировать технические характеристики, как память или потребление CPU, но бизнесу еще может быть интересно, чтобы разработка шла быстро и не стоила как космический корабль. Параллельный код может быть дороже и сложнее.
Ну и ты еще исходишь из предположения, что запросы к БД это самая долгая часть выполнения скрипта. Я смотрел трейсы в PHP-приложениях, и могу сказать, что это далеко не всегда так. Оптимизированный запрос с индексами на хорошем сервере может выполняться меньше 1 мс. Нужно ли его распараллеливать?
На Питоне все SQL запросы выполняют параллельно? Теперь уже я удивлен, первый раз про такое слышу. Покажи-ка ссылочку.
Если тебе все равно хочется отправлять параллельные запросы, я бы начал с изучения фреймворка ReactPHP и поиска асинхронного драйвера для БД. По моему, mysqli что-то такое может уметь, но я не уверен.
Зависит от ситуации и заказчика. Если ты учишься, то я бы советовал хоть раз сделать идеально. А так, конечно, важно, чтобы выглядело так, как задумал дизайнер, чтобы все было выровнено (частая проблема - выравнивание иконок относительно кнопок или текста). Иногда бывает, что на макете дизайнер поленился все до конца выровнять и приходится выравнивать за него.
А что мешает делать, как на макете?
>>23581
> $text = str_ireplace(" ", null, $text);
Заменять на null нелогично, так как в строку можно вставить только другую строку (например, пустую). Также, ireplace тут использовать нелогично, так как тут не нужна проверка регистра символов. Ну, и наконец, хочу сообщить, что эта функция в принципе нерабочая (в том, что касается регистра символов): https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> $perebor1
можно было назвать char1
> };
Точка с запятой после такой скобки не нужна
А так, сделано верно.
>>23576
В PHP был так называемый safe mode, где ставились разные ограничения, но это все работало плохо и всегда находились какие-то обходные пути. Глупо пытаться ограничивать программу, работая на том же уровне привилегии, то есть имея равные с ней возможности. Для твоей задачи больше подойдет такой подход:
- сделать в linux отдельного пользователя
- запускать приложения из-под него
- с помощью iptables настроить список IP, с которыми он может соединяться. Чтобы он не сливал данные через DNS, вместо доступа к настоящему DNS даем ему доступ только к своему DNS-серверу, который резолвит только жестко прописанные в конфиге имена доменов (это умеет делать dnsmasq, я такое делал для того, чтобы телефон не мог сливать данные через DNS запросы).
- как альтернатива, можно вообще не давать прямого доступа в сеть, а перенаправлять трафик на squid (как прозрачный прокси, прозрачный тут значит, что клиент о нем не подозревает), в котором настроить правила фильтрации
Также, ты можешь подключить сервер со своим приложением через фаерволл и фильтровать трафик на нем, если ты богат.
Я так фильтровал трафик с андроид-телефона: все DNS-запросы шли на dnsmasq, все HTTP-соединения перехватывались и отправлялись в squid, все остально резалось. Возни, конечно, много, пока во всем этом разберешься и отладишь, сразу скажу, что чтением документации вряд ли обойдешься. Мне пришлось даже немного пропатчить сквид ради такого перехвата HTTPS, который мне был нужен, с подменой сертификатов.
Если все равно хочется сделать по-простому, то возьми расширение runkit и перехвати с его помощью функции, работающие с DNS, но конечно, это можно будет обойти.
Зависит от ситуации и заказчика. Если ты учишься, то я бы советовал хоть раз сделать идеально. А так, конечно, важно, чтобы выглядело так, как задумал дизайнер, чтобы все было выровнено (частая проблема - выравнивание иконок относительно кнопок или текста). Иногда бывает, что на макете дизайнер поленился все до конца выровнять и приходится выравнивать за него.
А что мешает делать, как на макете?
>>23581
> $text = str_ireplace(" ", null, $text);
Заменять на null нелогично, так как в строку можно вставить только другую строку (например, пустую). Также, ireplace тут использовать нелогично, так как тут не нужна проверка регистра символов. Ну, и наконец, хочу сообщить, что эта функция в принципе нерабочая (в том, что касается регистра символов): https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> $perebor1
можно было назвать char1
> };
Точка с запятой после такой скобки не нужна
А так, сделано верно.
>>23576
В PHP был так называемый safe mode, где ставились разные ограничения, но это все работало плохо и всегда находились какие-то обходные пути. Глупо пытаться ограничивать программу, работая на том же уровне привилегии, то есть имея равные с ней возможности. Для твоей задачи больше подойдет такой подход:
- сделать в linux отдельного пользователя
- запускать приложения из-под него
- с помощью iptables настроить список IP, с которыми он может соединяться. Чтобы он не сливал данные через DNS, вместо доступа к настоящему DNS даем ему доступ только к своему DNS-серверу, который резолвит только жестко прописанные в конфиге имена доменов (это умеет делать dnsmasq, я такое делал для того, чтобы телефон не мог сливать данные через DNS запросы).
- как альтернатива, можно вообще не давать прямого доступа в сеть, а перенаправлять трафик на squid (как прозрачный прокси, прозрачный тут значит, что клиент о нем не подозревает), в котором настроить правила фильтрации
Также, ты можешь подключить сервер со своим приложением через фаерволл и фильтровать трафик на нем, если ты богат.
Я так фильтровал трафик с андроид-телефона: все DNS-запросы шли на dnsmasq, все HTTP-соединения перехватывались и отправлялись в squid, все остально резалось. Возни, конечно, много, пока во всем этом разберешься и отладишь, сразу скажу, что чтением документации вряд ли обойдешься. Мне пришлось даже немного пропатчить сквид ради такого перехвата HTTPS, который мне был нужен, с подменой сертификатов.
Если все равно хочется сделать по-простому, то возьми расширение runkit и перехвати с его помощью функции, работающие с DNS, но конечно, это можно будет обойти.
Ну вот, жаль, что так получается, что человек, который в нашем треде учился - и не может найти нормальную работу. Если у тебя есть возможность, я советую попробовать все же изучать технологии более глубоко - в ОП посте, например, есть задача на TestHub, которую можно делать на Симфони, ну и конечно, подучить то, что плохо знаешь - ООП там, HTTP, linux, тестирование. Может, изучить современные сложные JS фреймворки. Развиваться, расширять кругозор. А то иначе, если изучить только основы, то ты будешь конкурировать с тысячами таких же начинающих.
Если же ты все это знаешь, то может, ты подаешь себя как-то не так. Не представляю, чтобы человек с такими знаниями не мог найти работу.
> не знаю досконально Wordpress,
Поставь его себе на локалхост, изучи админку, прочитай пяток статей в стиле "лучшие плагины для вордпресс в 2017", поставь себе эти плагины. Этого уже хватит, чтобы какие-то простые задачи делать. Дальше, почитай документацию, сделай какой-нибудь простой плагин, сделай тему для ВП и в общем-то это и все, что обычно требуется от ВП разработчика.
Но конечно, в некоторых задачах требуется знать гораздо больше. Вот например, тебе скажут "сайт тормозит" - и тут надо будет смотреть его разными инструментами (htop, strace), профайлить, может, оптимизировать SQL запросы, настраивать кеширование - то есть тут уже нужен другой уровень, нужно знание линукса, индексов в SQL итд. Обычный "разработчик ВП" не справится (я с такой ситуацией сталкивался).
Мы, кстати, этому всему можем помочь научиться, по крайней мере, ссылками, задачками и ответами на вопросы.
>>23325
Я обычно не комментирую такие сообщения, но всегда приятно их читать. И можно будет, если что, показывать их новичкам для мотивации или даже повесить на сайт в раздел "отзывы" (не знаю, впрочем, будут ли они вызывать доверие).
>>22771
Вот, вот, такой отзыв я и ждал. Смотрите все, аноны, как важно изучать linux, ООП, фреймворки и автоматизированное тестирование, а не ограничиваться основами. А то что-то редко я тут вижу вопросы по этим темам. Наш тред этому тоже вас научит, если будет желание с вашей стороны.
Не надо конкурировать с настройщиками вордпресса, вы по цене их не перебьете.
Ну вот, жаль, что так получается, что человек, который в нашем треде учился - и не может найти нормальную работу. Если у тебя есть возможность, я советую попробовать все же изучать технологии более глубоко - в ОП посте, например, есть задача на TestHub, которую можно делать на Симфони, ну и конечно, подучить то, что плохо знаешь - ООП там, HTTP, linux, тестирование. Может, изучить современные сложные JS фреймворки. Развиваться, расширять кругозор. А то иначе, если изучить только основы, то ты будешь конкурировать с тысячами таких же начинающих.
Если же ты все это знаешь, то может, ты подаешь себя как-то не так. Не представляю, чтобы человек с такими знаниями не мог найти работу.
> не знаю досконально Wordpress,
Поставь его себе на локалхост, изучи админку, прочитай пяток статей в стиле "лучшие плагины для вордпресс в 2017", поставь себе эти плагины. Этого уже хватит, чтобы какие-то простые задачи делать. Дальше, почитай документацию, сделай какой-нибудь простой плагин, сделай тему для ВП и в общем-то это и все, что обычно требуется от ВП разработчика.
Но конечно, в некоторых задачах требуется знать гораздо больше. Вот например, тебе скажут "сайт тормозит" - и тут надо будет смотреть его разными инструментами (htop, strace), профайлить, может, оптимизировать SQL запросы, настраивать кеширование - то есть тут уже нужен другой уровень, нужно знание линукса, индексов в SQL итд. Обычный "разработчик ВП" не справится (я с такой ситуацией сталкивался).
Мы, кстати, этому всему можем помочь научиться, по крайней мере, ссылками, задачками и ответами на вопросы.
>>23325
Я обычно не комментирую такие сообщения, но всегда приятно их читать. И можно будет, если что, показывать их новичкам для мотивации или даже повесить на сайт в раздел "отзывы" (не знаю, впрочем, будут ли они вызывать доверие).
>>22771
Вот, вот, такой отзыв я и ждал. Смотрите все, аноны, как важно изучать linux, ООП, фреймворки и автоматизированное тестирование, а не ограничиваться основами. А то что-то редко я тут вижу вопросы по этим темам. Наш тред этому тоже вас научит, если будет желание с вашей стороны.
Не надо конкурировать с настройщиками вордпресса, вы по цене их не перебьете.
Прежде чем говорить про ТДД, мы должны поговорить про экономическое обоснование автоматического тестирования. Написание и настройка тестов требует времени (=денег), и нам надо понять, как эти расходы окупаются.
Считается, что выгода тестов в том, что при многократном запуске мы тратим время на их написание только первый раз, а второй и далее запуски нам бесплатны (в отличие от ручного тестирование, где каждый прогон стоит денег). Плюс, автоматические тесты выполняются быстрее. Следовательно, автоматические тесты могут окупаться там, где их многократно запускают.
Использование тестов также позволяет разработчикам более смело делать большие рефакторинги и изменения в коде. Тесты позволяют "защитить" однажды написанный функционал от повреждения, позволяют раньше находить ошибки и повысить качество кода.
Оправданно ли это в верстке, если ты делаешь ее один раз, проверяешь визуально и сдаешь заказчику? Оправданно ли это, если ты поддерживаешь и дорабатываешь верстку в течение долгого времени?
----
Теперь поговорим, как именно можно применить ТДД к верстке. Я не большой знаток ТДД, потому пролистал википедию по этой теме и первый вопрос, который у меня возник, а какие мы будем писать сценарии и что можно тестировать в верстке? Какие требования мы к ней хотим предъявить и проверить их соблюдение? Что мы будем считать критерием "хорошей" верстки?
- "заголовок должен быть черного цвета, крупнее основного текста и прижат влево"?
- "картинка должна быть отцентрирована в блоке вертикально"?
- "карточка отеля не должна разваливаться, даже если у отеля очень длинное название"? (это, кстати, мне уже нравится)
- "карточка отеля должна отображаться корректно, на какую бы страницу мы ее не вставили"?
- "карточка отеля на мобильной версии с узким экраном не должна вылезать за его пределы"?
- "карточка отеля должна выглядеть в ИЕ9 аналогично виду в Хроме"?
Так, боюсь, нам придется очень долго и подробно описывать макет в виде кода, и это сомнительная затея. Представь сам, сколько в макете независимых элементов, и сколько надо для них написать правил.
Я, кстати, советовал бы использовать методологию вроде БЭМ и разбивать верстку на независимые блоки - это здорово упростит проверку, облегчит поддержку и повысит пуленепробиваемость верстки.
Вместо того, чтобы описывать ожидаемый результат кодом, мы можем сделать что-то другое. Мы можем сверстать элемент, проверить на глаз, что он выглядит корректно, и сохранить его внешний вид - может быть, в виде скриншота, может быть в виде куска DOM с проставленным размерами и координатам элементов (скриншоты могут немного различаться в разных ОС и браузерах из-за особенностей рендеринга шрифтов, видеокарт и тд). И после этого мы можем написать тест, проверяющий, что после изменений в верстке данный блок не поменял внешний вид.
Но это будет не совсем TDD, боюсь. Там ведь мы пишем тесты сначала. Хотя, может, можно придумать какой-то текстовый формат описания внешнего вида блока и сделать на его основе тест (в идеале - вообще генерировать из макета, но тут может понадобиться машинное зрение и искуственный интеллект). Но не уверен, что это будет быстро.
Также, можно попробовать подключить инструменты для валидации кода - они тоже могут что-нибудь находить.
Еще можно придумать какие-то простые тесты в стиле "вставляем данные в БД, загружаем страницу, проверяем их наличие" или "загружаем страницу, проверяем, что в логе пхп нет ошибок". Может, тут надо только часть задач автоматизировать.
Могу дать еще ссылки про тестирование верстки:
- https://habrahabr.ru/company/yandex/blog/200968/
- https://habrahabr.ru/company/2gis/blog/277457/ (тут вроде ручные тесты)
- https://habrahabr.ru/post/114256/ (ручные)
- https://events.yandex.ru/lib/talks/?audience=testirovschiki
- https://readymag.com/tehnovedro/488569/5/
- https://habrahabr.ru/post/271379/
- https://toster.ru/q/373556
Если у тебя есть каике-то интересные идеи, и тем более, ты готов их испробовать, мне было бы очент интересно почитать, и я может быть могу где-то помочь советом. Мне это интересно, так как у нас есть задачи на CSS и мне было бы пригодилась возможность автоматически проверять их решения.
Прежде чем говорить про ТДД, мы должны поговорить про экономическое обоснование автоматического тестирования. Написание и настройка тестов требует времени (=денег), и нам надо понять, как эти расходы окупаются.
Считается, что выгода тестов в том, что при многократном запуске мы тратим время на их написание только первый раз, а второй и далее запуски нам бесплатны (в отличие от ручного тестирование, где каждый прогон стоит денег). Плюс, автоматические тесты выполняются быстрее. Следовательно, автоматические тесты могут окупаться там, где их многократно запускают.
Использование тестов также позволяет разработчикам более смело делать большие рефакторинги и изменения в коде. Тесты позволяют "защитить" однажды написанный функционал от повреждения, позволяют раньше находить ошибки и повысить качество кода.
Оправданно ли это в верстке, если ты делаешь ее один раз, проверяешь визуально и сдаешь заказчику? Оправданно ли это, если ты поддерживаешь и дорабатываешь верстку в течение долгого времени?
----
Теперь поговорим, как именно можно применить ТДД к верстке. Я не большой знаток ТДД, потому пролистал википедию по этой теме и первый вопрос, который у меня возник, а какие мы будем писать сценарии и что можно тестировать в верстке? Какие требования мы к ней хотим предъявить и проверить их соблюдение? Что мы будем считать критерием "хорошей" верстки?
- "заголовок должен быть черного цвета, крупнее основного текста и прижат влево"?
- "картинка должна быть отцентрирована в блоке вертикально"?
- "карточка отеля не должна разваливаться, даже если у отеля очень длинное название"? (это, кстати, мне уже нравится)
- "карточка отеля должна отображаться корректно, на какую бы страницу мы ее не вставили"?
- "карточка отеля на мобильной версии с узким экраном не должна вылезать за его пределы"?
- "карточка отеля должна выглядеть в ИЕ9 аналогично виду в Хроме"?
Так, боюсь, нам придется очень долго и подробно описывать макет в виде кода, и это сомнительная затея. Представь сам, сколько в макете независимых элементов, и сколько надо для них написать правил.
Я, кстати, советовал бы использовать методологию вроде БЭМ и разбивать верстку на независимые блоки - это здорово упростит проверку, облегчит поддержку и повысит пуленепробиваемость верстки.
Вместо того, чтобы описывать ожидаемый результат кодом, мы можем сделать что-то другое. Мы можем сверстать элемент, проверить на глаз, что он выглядит корректно, и сохранить его внешний вид - может быть, в виде скриншота, может быть в виде куска DOM с проставленным размерами и координатам элементов (скриншоты могут немного различаться в разных ОС и браузерах из-за особенностей рендеринга шрифтов, видеокарт и тд). И после этого мы можем написать тест, проверяющий, что после изменений в верстке данный блок не поменял внешний вид.
Но это будет не совсем TDD, боюсь. Там ведь мы пишем тесты сначала. Хотя, может, можно придумать какой-то текстовый формат описания внешнего вида блока и сделать на его основе тест (в идеале - вообще генерировать из макета, но тут может понадобиться машинное зрение и искуственный интеллект). Но не уверен, что это будет быстро.
Также, можно попробовать подключить инструменты для валидации кода - они тоже могут что-нибудь находить.
Еще можно придумать какие-то простые тесты в стиле "вставляем данные в БД, загружаем страницу, проверяем их наличие" или "загружаем страницу, проверяем, что в логе пхп нет ошибок". Может, тут надо только часть задач автоматизировать.
Могу дать еще ссылки про тестирование верстки:
- https://habrahabr.ru/company/yandex/blog/200968/
- https://habrahabr.ru/company/2gis/blog/277457/ (тут вроде ручные тесты)
- https://habrahabr.ru/post/114256/ (ручные)
- https://events.yandex.ru/lib/talks/?audience=testirovschiki
- https://readymag.com/tehnovedro/488569/5/
- https://habrahabr.ru/post/271379/
- https://toster.ru/q/373556
Если у тебя есть каике-то интересные идеи, и тем более, ты готов их испробовать, мне было бы очент интересно почитать, и я может быть могу где-то помочь советом. Мне это интересно, так как у нас есть задачи на CSS и мне было бы пригодилась возможность автоматически проверять их решения.
Памяти достаточно? В своп не выпадает? Смотри диспетчером задач хотя бы.
>>22962
Вот, кстати, с точки зрения ООП, это очень странный код. Если ты хочешь вызвать обычный метод, то ествественно, нужно иметь экземпляр объекта. Если ты создаешь объект и тут же выкидываешь, то не очень понятно, а не проще ли метод сделать статическим. И если это обычный метод, то не проще ли его вызывать как обычный. Вот такое отношение к ООП мне в ларавеле не нравится.
Также, узнать, какие функции вызываются в ходе работы программы, можно, освоив xdebug и сделав трейс, и да!!!, я все еще интересуюсь, не хочет ли кто сделать визуализатор логов трассировки? Ссылка: https://xdebug.org/docs/execution_trace
>>22993
Конечно, стоит изучить готовые решения.
>>22967
Насчет роутов в YAML - это очень помогает, когда, например, у тебя много роутов, и ты можешь посмотреть, как добавить новый, чтобы он не конфликтовал со старыми и можешь даже настроить их порядок вручную. А что делать в случае аннотаций? Также, к роутам можно писать регулярки для параметров, опять же, наверно, неудобно писать их в аннотациях. Ну и наконец, при желании к роутам можно писать дополнительные опции (права доступа, правила переключения на другую страну, настройки кеширования - но учти, что они в Симфони вроде не кешируются и надо это исправить сначала) и тут YAML файл очень удобен.
Также, в конфиге роутинга несколько роутов могут вести на одно действие, но с разными параметрами.
Я не представляю, как со всем этим работать в аннотациях. Придется постоянно вызывать команду, дампящую роуты и смотреть результат. неудобно же, когда 200 роутов раскиданы где-то по коду. Единственный плюс - при удалении контроллера роут удаляется вместе с ним.
Но это мое субъективное мнение.
Что касается @ParamConverter, это же часть контроллера, его можно наверно оставить в аннотации. Нельзя? Предложи исправить это.
Смотри настройки гит-плагина, а также погугли, не баг ли это.
>>22873
Транзакции нужны, если запросов больше одного. Если у тебя один INSERT, он и так идет как одна транзакция.
Проще наверно просто игнорировать кривые куки. А то вдруг админ удалит студента, а он пытается зайти на сайт.
> Фейкер умеет только в женское имя и ФИО.
Не хочешь допилить и поделиться решением со всеми? Придется расковырять фейкер, понять, как он рабоатет, и может обсудить это с его разработчиками.
как вы заебали, реально. вот тебе на дваче скажут "нет смысла, иди таксистом рабоать" и что дальше? пойдешь?
если хочешь чем-то заниматься, должно быть похуй на чужие мнения. иначе будешь вяло подрачивать и "вкатываться" пять лет. а потом не вкатишься и скажешь "ну да, меня не берут потому что мне 26".
короче иди учи
сделай что говорит
сам бэкендом занимаюсь, верстку умею на уровне потыкать бутстрап, поэтому нихуя не шарю в тонкостях
Кроме IE есть еще Edge и Safari
И у самого IE несколько версий
А вообще зуй щнает, я не могу заниматься версткой без фотошопа. Мне все макеты так или иначе приходят в psd
Впервые тут у вас. Заглянул в первый гайд для новичков в шапке и охуел.
Кто и зачем так постарася?
Гайд правда толковый или только выглядит так?
>Гайд правда толковый или только выглядит так?
Это лучший гайд, на мой взгляд. Книжек нормальных по пхп нет, только мануал очень хороший.
Я вот просто на физическом уровне пытаюсь представить распаралеленный запрос к бд и что-то не могу. Просто потому-что знаю как устроены запросы внутри большинства бд. Ну тоесть допустим у тебя есть "Select from users" и "Select from questions" (это гипотетические запросы выдуманные для примера, не надо до синтаксиса докапываться).
И обычная скажем MSSQL смотрит когда был подан запрос и тупо выполняет сначала тот который был раньше, а потом тот который был позже.
А тут как ты себе представляешь это? Сначала БД выбирает первую запись первого запроса, потом первую запись второго, и так пока до конца не дойдёт? Что-то тут не так мне кажется.
С микросервисами так можно, если у тебя данные для разных частей страницы формируют разные микросервисы, работающие на разных серверах, то можно параллельно им запросы отправить.
ну там не то чтобы прямо верстка по макету, просто у друга условный автосервис, он заказал сайт "шоб читалось легко". и главное не объебаться с тем, что везде все нормально, а в
ИЕ все пополам складывается.
я для себя выделил такие аргументы против использования готовых пакетов:
1. сложно дебажить
2. нет предупреждений об утечках памяти
3. нельзя использовать thread safety
4. возможная несовместимость патчей внутри одного пакета
я на своем опыте сталкивался только с проблемой того, что нельзя использовать pthreads. но там ясно в мануале написано мол хотите использовтаь - перекомпилируйте с каким-то там ключом.
кто-то реально заморачивается с самостоятельной пересборкой? допустим, есть некий хостинг, они когда обновляют версию, они сами ее компилируют из исходников?
1. files (
id
name
size
linkaname
created_at
updated_at
lifetime
user_id
public
comment
status)
2.comments (
id
user_id
parent_id
child_id
comment)
//Вообще для комментариев будет две базы данных для реализации древовидных комментариев. Здесь просто указаны поля
3.users (
id
name
avatar?
hash)
Ну и собственно вопрос. Нормально ли что у меня в таблице files столько столбцов? Есть ли какое-то ограничение на колличество? Ну и вообще правильно ли спроектировал?
1. files (
id
name
size
linkaname
created_at
updated_at
lifetime
user_id
public
comment
status)
2.comments (
id
user_id
parent_id
child_id
comment)
//Вообще для комментариев будет две базы данных для реализации древовидных комментариев. Здесь просто указаны поля
3.users (
id
name
avatar?
hash)
Ну и собственно вопрос. Нормально ли что у меня в таблице files столько столбцов? Есть ли какое-то ограничение на колличество? Ну и вообще правильно ли спроектировал?
сколько столбцов надо, столько и нормально. вроде нормально, но приложи еще внешние ключи для того, чтобы удостовериться.
также по поводу вложенных комментариев, у ОПа есть урок https://github.com/codedokode/pasta/blob/master/db/trees.md
где он предлагает для реализации closure table (которую ты, судя по всему, вырбал) использовать дополнительную таблицу связей. ты же кладешь parent_id и child_id в ту же таблицу комментов, а поле указания глубины не используешь. в итоге как ты собираешься строить структуру комментариев?
от себя добавлю, я бы использовал nested_sets, они быстры на выборку, а для манипуляций с перемещением-удалением есть библиотеки для той же Доктрины (наверняка еще миллион standalone). если конечно не стоит задачи написать все самому.
Древовидные комментарии уже реализовывал отдельно. Все получилось, как раз клоужер тейбл использовал.
Внешние ключи.
files id, user_id
comments user_id, id
users id
передача аргументов по ссылке устарело?
на случай, если ты не передашь этот конкретный параметр. значение по умолчанию в качестве аргумента значит, что этот аргумент необязательный.
что значит устарело? deprecated? нет, оно не депрекейтед, если ты имеешь в виду указание ссылки в определении функции типа
function foo(&$number) {...}
а вот указание ссылки при ВЫЗОВЕ функции с 5.4 (кажется, точно не помню) запрещено:
function foo($number) {...}
$a = 5;
echo foo(&a); // это вызовет ошибку
Как отрефакторить пхп так, чтоб нельзя было уличить в плагиаторстве?
Помимо очевидного переименовывания переменных и функций
> сложно дебажить
На продакшен сервере не дебажат. На память просто поебать. Тем не менее, у нас он скомпилирован админом вместе с использованными нами библиотеками. Дополнительно он там какие-то заплатки прикомпилил, чтобы не похакали. Из минусов только то, что при необходимости добавить или поменять библиотеку приходится дергать админа, чтобы он все заново перекомпилил.
Вообще, это возможно. Обычно да, в рамках одного соединения запросы выполняются последовательно. Но базы данных обычно многопоточные/многопроцессные и можно открыть несколько соединений и выполнять несколько запросов.
Но важно понимать, что тот же дисковый трафик и число процессоров ограничены и нужно подобрать такие параметры распараллеливания, которые смогут задействовать имеющиеся ресурсы максимально.
Если тебе интересно про то, как с точки зрения архитектуры устроены серверы, в том числе СУБД, есть паста: https://gist.github.com/codedokode/ffd520440a970c07c1c6
>>23273
Вот кстати в mysqli есть асинхронные запросы, можно еще в эту сторону копать: http://php.net/manual/ru/mysqli.poll.php
>>24222
Я стараюсь у себя локально использовать готовые пакеты, так как это быстрее. Расширения тоже ставлю через apt-get, а если их там нет, то под линуксом они легко компилируются одной командой через pecl install.
Я думаю, что сборка из исходников нужна тем, кто разрабаитывает интерпретатор PHP или исследует баги в нем.
Также, есть набор скриптов phpenv, который позволяет автоматизировать установку версий PHP, и даже ставить их несколько на один компьютер.
> 1. сложно дебажить
Ну, мне это и не требуется и я не силен в gdb
Вообще, по поводу отладочных данных, мне нравится, как это сделано у майкрософт: у них отладочные данные идут в отдельном pdb-файле, а не встраиваются в exe-шник.
> 2. нет предупреждений об утечках памяти
Это да. Но я не сталкивался с проблемами из-за них.
> 3. нельзя использовать thread safety
Версия PHP под винду, кстати, thread-safe.
> кто-то реально заморачивается с самостоятельной пересборкой? допустим, есть некий хостинг, они когда обновляют версию, они сами ее компилируют из исходников?
Думаю, они используют phpenv или что-то аналогичное. Хотя, собрать PHP не так и сложно. Я, например, собирал PHP7 под XP (пришлось чуть-чуть пропатчить), а под линуксом это вообще стандартно делается, configure + make + make install.
Вообще, это возможно. Обычно да, в рамках одного соединения запросы выполняются последовательно. Но базы данных обычно многопоточные/многопроцессные и можно открыть несколько соединений и выполнять несколько запросов.
Но важно понимать, что тот же дисковый трафик и число процессоров ограничены и нужно подобрать такие параметры распараллеливания, которые смогут задействовать имеющиеся ресурсы максимально.
Если тебе интересно про то, как с точки зрения архитектуры устроены серверы, в том числе СУБД, есть паста: https://gist.github.com/codedokode/ffd520440a970c07c1c6
>>23273
Вот кстати в mysqli есть асинхронные запросы, можно еще в эту сторону копать: http://php.net/manual/ru/mysqli.poll.php
>>24222
Я стараюсь у себя локально использовать готовые пакеты, так как это быстрее. Расширения тоже ставлю через apt-get, а если их там нет, то под линуксом они легко компилируются одной командой через pecl install.
Я думаю, что сборка из исходников нужна тем, кто разрабаитывает интерпретатор PHP или исследует баги в нем.
Также, есть набор скриптов phpenv, который позволяет автоматизировать установку версий PHP, и даже ставить их несколько на один компьютер.
> 1. сложно дебажить
Ну, мне это и не требуется и я не силен в gdb
Вообще, по поводу отладочных данных, мне нравится, как это сделано у майкрософт: у них отладочные данные идут в отдельном pdb-файле, а не встраиваются в exe-шник.
> 2. нет предупреждений об утечках памяти
Это да. Но я не сталкивался с проблемами из-за них.
> 3. нельзя использовать thread safety
Версия PHP под винду, кстати, thread-safe.
> кто-то реально заморачивается с самостоятельной пересборкой? допустим, есть некий хостинг, они когда обновляют версию, они сами ее компилируют из исходников?
Думаю, они используют phpenv или что-то аналогичное. Хотя, собрать PHP не так и сложно. Я, например, собирал PHP7 под XP (пришлось чуть-чуть пропатчить), а под линуксом это вообще стандартно делается, configure + make + make install.
> linkaname
> created_at
Надо писать названия в едином стиле, по умолчанию можно использовать SQL style guide http://www.sqlstyle.guide/ru/
Не забудь также комментарии к неочевидным колонкам ( https://github.com/codedokode/pasta/blob/master/db/comments.md )
Не забудь внешние ключи, ограничения уникальности полей. Если твоя БД поддерживает ограничение CHECK (например: postgres и sqlite), используй его там, где это уместно.
comment лучше наверно заменить на description.
Про древовидные данные в БД есть урок, если что: https://github.com/codedokode/pasta/blob/master/db/trees.md
> Нормально ли что у меня в таблице files столько столбцов?
Да
> Есть ли какое-то ограничение на колличество?
да, изучи документацию по твоей БД или набери в Гугл <db> columns limit.
> Ну и вообще правильно ли спроектировал?
Выглядит верно.
>>24346
Я бы советовал сравнить плюсы и минусы разных вариантов реализации деревьев и попробовать выбрать наиболее подходящий ответ. А потом сравнить с тем, что я написал ниже:
Для комментариев чаще всего применяют (не заглядывайте раньше времени) material path material path material path
>>24371
> Все получилось, как раз клоужер тейбл использовал
Попробуй оценить ее размер в зависимости от числа файлов, средненго числа комментариев, средней глубины ответов. Попробуй оценить число SQL запросов (выборок, вставок) при добавлении нового комментария.
>>24432
Объект передается как будто по ссылке. Если быть точным, то в PHP объекты хранятся в отдельной области памяти, а в переменной хранится лишь идентификатор (указатель) объекта. И ты передаешь в функцию не копию объекта, а просто его идентификатор. Чтобы сделать копию, используется оператор clone.
> linkaname
> created_at
Надо писать названия в едином стиле, по умолчанию можно использовать SQL style guide http://www.sqlstyle.guide/ru/
Не забудь также комментарии к неочевидным колонкам ( https://github.com/codedokode/pasta/blob/master/db/comments.md )
Не забудь внешние ключи, ограничения уникальности полей. Если твоя БД поддерживает ограничение CHECK (например: postgres и sqlite), используй его там, где это уместно.
comment лучше наверно заменить на description.
Про древовидные данные в БД есть урок, если что: https://github.com/codedokode/pasta/blob/master/db/trees.md
> Нормально ли что у меня в таблице files столько столбцов?
Да
> Есть ли какое-то ограничение на колличество?
да, изучи документацию по твоей БД или набери в Гугл <db> columns limit.
> Ну и вообще правильно ли спроектировал?
Выглядит верно.
>>24346
Я бы советовал сравнить плюсы и минусы разных вариантов реализации деревьев и попробовать выбрать наиболее подходящий ответ. А потом сравнить с тем, что я написал ниже:
Для комментариев чаще всего применяют (не заглядывайте раньше времени) material path material path material path
>>24371
> Все получилось, как раз клоужер тейбл использовал
Попробуй оценить ее размер в зависимости от числа файлов, средненго числа комментариев, средней глубины ответов. Попробуй оценить число SQL запросов (выборок, вставок) при добавлении нового комментария.
>>24432
Объект передается как будто по ссылке. Если быть точным, то в PHP объекты хранятся в отдельной области памяти, а в переменной хранится лишь идентификатор (указатель) объекта. И ты передаешь в функцию не копию объекта, а просто его идентификатор. Чтобы сделать копию, используется оператор clone.
>Вообще для комментариев будет две базы данных для реализации древовидных комментариев.
1. Прекрати называть таблицу базой данных. У тебя три таблицы в одной базе.
2. На вскидку, я не вижу повода создавать две таблицы для древовидных комментов. Просто каждая запись комментария будет содержать поле со ссылкой на предыдущий комментарий.
Получилось сделать так, чтоб выводил элементы в столбик.
Как сделать в виде таблицы (по 2-3 элемента в строку)?
В теге <style> прописал такой вот код для вывода в столбик:
#results .result .image {height: 200px;width: 300px;float: left;padding: 2px;overflow: hidden;position:relative;}
#results .result .image img {width:300px;}
#results .result .image p {position: absolute;top: 85px;margin: 5px;padding: 0px;color: white;text-rendering:optimizelegibility;text-shadow: 0 0 3px rgba(0, 0, 0, .8);}
#results .result .stats {width:260px;float:right;}
Это не позволяет эффективно выбирать комментарии. Почитай урок https://github.com/codedokode/pasta/blob/master/db/trees.md
я тут впс поднял и на нем захуярил гит-сервер (gogs.io). не хочу, чтобы туда всякие левые чуваки регистрировались и вообще он только для меня и полутора коллег. а он там по умолчанию открыт для всех и пиздец. можно прямо из интернета зайти, зарегить сто аккаунтов и пожрать мне все ресурсы.
какие есть варианты вменяемо ограничить доступ ко всему домену? знаю вариант поднимать vpn сервер и пускать к гиту только через тоннель, но это чуток заебно, т.к. во-первых, vpn пожрет и так ограниченные ресурсы впс, а во-вторых, надо впн поднимать на клиенте, отсылать ему файл с конфигом и прочее. не хочется заморачиваться.
в идеале на уровне конфига нжинкса повесить какую-то авторизацию по ключу, например. есть какой-то такой вариант?
Вот ты жмотяра, пиздец. Нахуй так жить вообще. Уууу, чтоб ты сдох нахуй и семья твоя вся сдохла. Пидор, уебок, жлобяра.
Пример записей, которые должно показывать приложение:
1. "23 января 1905 г. день рождение Антона Голубцова, напомнить 22 января 2018 г."
2. "01 июля 2018 г. свадьба Антона Голубцова и Тани Яотиной, напомнить 25 июня 2018 г. (купить подарок), 30 июля 2018 г. (помыться)"
Записи можно сортировать по датам, по событиям, по участникам. Напоминаний и участников у события может быть несколько. Типы событий можно добавлять.
Представил как одним запросом СУБД захватывает аж 6 таблиц и немного погрустнел. И ведь целая система нормализации есть. Только непонять в чём профит, столько данных тащить. На ум приходит только тотальная и маниакальная экономия дискового пространства.
>Представил как одним запросом СУБД захватывает аж 6 таблиц и немного погрустнел
хуяк-хуяк подобрал индексы шоб ниормазило и в продакшон. Чо ты как нипацан.
>в идеале на уровне конфига нжинкса повесить какую-то авторизацию по ключу, например. есть какой-то такой вариант?
Ну естественно так и надо делать. Это для доступа по ssh. И не забудь после отключить доступ по паролю.
А если у тебя есть веб-морда к серверу, то очевидно нужно закрыть доступ для незарегистрированных в системе юзеров - проще говоря страницу логина добавь, если таковой по умолчанию нет.
про доступ по ssh это да. но у меня грубо говоря есть сайт, к которому я хочу ограничить доступ. есть возможность в https логиниться по ключу?
Нет, такой возможности нет. Зачем тебе это нужно вообще? Настрой ssh доступ и делай пулы/пуши через ssh. Ну либо по https - но нужен будет пароль.
Тебе нужно ограничить доступ к веб-морде? Используй страницу логина либо, если известны адреса клиентов, добавь их в белый список веб-сервера, а остальным айпи просто заблокируй доступ.
>Надо писать названия в едином стиле, по умолчанию можно использовать SQL style guide http://www.sqlstyle.guide/ru/
Поясните, пожалуйста, с чем связана такая рекомендация?
Посоны, у меня вопрос по базам данных. Какие ключи лучше использовать - автоинкрементальные или генерируемые? Какие недостатки/преимущества есть у тех и других?
Я вижу серьёзное преимущество генерируемых в том, что при добавлении записи во множество таблиц, мне не нужно сначала вставлять данные в основную таблицу, получать автоинкрементальный айди и потом только делать вставку с этим айди в дочерние таблицы. Я просто генерирую айди и распихиваю связанные по этому айди данные в нужные таблицы без лишних телодвижений.
Единственный серьёзный недостаток, который я вижу в генерации, это возможность коллизий. Но всегда можно подобрать алгоритм генерации, который сведёт такие случаи к нулю.
вот эти рекомендации тоже особо никто не выполняет:
>Всегда используйте ключевое слово AS для лучшей читаемости.
>По возможности избегайте объединения названий двух таблиц для построения таблицы отношений. Например, вместо названия cars_mechanics лучше подойдёт services.
> Что касается @ParamConverter, это же часть контроллера, его можно наверно оставить в аннотации. Нельзя? Предложи исправить это.
До такого я не додумался. Попробую, посмотрю, как юудет
вопрос-то хороший. вот мои возражения:
1. в мускуле надо делать два запроса, а в постресе есть RETURNING.
2. по инкрементному айди можно отсортировать, а по сгенерированному нет.
3. генерация по-настоящему уникального значения - более дорогая операция.
4. он займет больше места для хранения и в теории поиск по индексу будет чуть медленнее.
по мне оно того не стоит
HTTP авторизация + используй HTTPS чтобы пароли было не подглядеть.
https://developer.mozilla.org/ru/docs/Web/HTTP/Авторизация
https://nginx.ru/ru/docs/http/ngx_http_auth_basic_module.html
>2. по инкрементному айди можно отсортировать, а по сгенерированному нет.
то есть, тебе надо заводить дополнительное поле для сортировки по нему. created_at не подойдет - в одну секунду может прилететь 10 записей. только если хранить microtime.
короче, для каких-то случаев может и проканает
Также есть более серьезная мера защиты - клиентские SSL сертификаты: https://habrahabr.ru/post/213741/
>>24744
role - не лучше ли сделать ENUM или foreign key на другую таблицу?
А у тебя предусмотрены ли периодические ивенты, например, день рождения по идее каждый год происходит.
Ключом в event_type наверно лучше сделать id. Он меньше места занимает.
Меня конечно беспокоит наличие похожих сущностей (users - participants, events - reminders), тут явно просится наследование или еще какое-то обобщение, но не станет ли из-за этого схема БД сложнее...
>>24745
Профит в том, что данные хранятся в единственном экземпляре и не может быть противоречий. Также, их легко редактировать, так как не надо искать все копии данных. Выгоды/недостатки нормализации давно изучены.
Насчет скорости выполнения запроса, джойны не проблема, если там джойнится например 1 запись и все это по индексам. Джойны - проблема, когда у тебя 2 больших таблицы и надо искать по обеим сразу и по каждой таблице поиск дает много результатов (например: найти компании с отделением в городе X, работающие в сфере Y, где связи компания-город и компания-сфера это многие-ко-многим).
Если номализованные данные работают медленно, всегда можно сделать денормализованную копию, в каком-нибудь отдельном хранилище, заточенном под поиск, вроде сфинкса или кеша. Но там свои подвохи.
Профит генерируемых ключей - возможность генерации на клиенте. Это годится в таких ситуациях: в моб. приложении при отсутствии связи с сервером, при отсутствии прямого доступа к БД (приложение генерирует сущность и связанные с ней, кладет в локальное хранилище, позже синхронизирует с центральной БД).
> Я вижу серьёзное преимущество генерируемых в том, что при добавлении записи во множество таблиц, мне не нужно сначала вставлять данные в основную таблицу, получать автоинкрементальный айди и потом только делать вставку с этим айди в дочерние таблицы. Я просто генерирую айди и распихиваю связанные по этому айди данные в нужные таблицы без лишних телодвижений.
Не очень понятно, а в чем тут выгода? Что мешает вставить сначала запись, а потом связанные с ней?
> Единственный серьёзный недостаток, который я вижу в генерации, это возможность коллизий. Но всегда можно подобрать алгоритм генерации, который сведёт такие случаи к нулю.
Да, и они давно уже придуманы.
>>24853
> по инкрементному айди можно отсортировать, а по сгенерированному нет.
Можно добавить дату вставки и сортировать по ней.
> генерация по-настоящему уникального значения - более дорогая операция
не думаю, есть алгоритмы.
>>24816
Я прочитал это предложение в англ. версии и там добавлено слово simply:
> Where possible avoid simply using id as the primary identifier for the table.
Также, в английской версии внизу есть ссылки на обсуждения: http://www.sqlstyle.guide/ и пояснения автора https://www.simonholywell.com/post/2016/12/sql-style-guide-misconceptions/?utm_source=sqlstyle.guide-sqlstyle.guide&utm_medium=link&utm_campaign=footer-link
> id columns and surrogate keys
> You do not need them [surrogate keys] in most cases as better keys often exist in the data already.
Также, можно попросить пояснений в issues: https://github.com/treffynnon/sqlstyle.guide/issues
Я думаю, речь о том, что если в данных есть естественный ключ, то рекомендуется использовать его, а не создавать искуственный. Но должен заметить, что у искуственных ключей есть преимущества, например:
- он останется ключом даже при смене условий задачи (ты сделал номер паспорта ключом, а потом узнал, что паспорта можно менять и в каких-то случаях иметь несколько)
- он мало весит, а размер полей влияет на размер индекса и объем требуемой под них памяти в больших таблицах. Индексы с 100-символьным колонками работают совсем не так хорошо, как индекс из интов (желательно подтвердить это тестом).
Профит генерируемых ключей - возможность генерации на клиенте. Это годится в таких ситуациях: в моб. приложении при отсутствии связи с сервером, при отсутствии прямого доступа к БД (приложение генерирует сущность и связанные с ней, кладет в локальное хранилище, позже синхронизирует с центральной БД).
> Я вижу серьёзное преимущество генерируемых в том, что при добавлении записи во множество таблиц, мне не нужно сначала вставлять данные в основную таблицу, получать автоинкрементальный айди и потом только делать вставку с этим айди в дочерние таблицы. Я просто генерирую айди и распихиваю связанные по этому айди данные в нужные таблицы без лишних телодвижений.
Не очень понятно, а в чем тут выгода? Что мешает вставить сначала запись, а потом связанные с ней?
> Единственный серьёзный недостаток, который я вижу в генерации, это возможность коллизий. Но всегда можно подобрать алгоритм генерации, который сведёт такие случаи к нулю.
Да, и они давно уже придуманы.
>>24853
> по инкрементному айди можно отсортировать, а по сгенерированному нет.
Можно добавить дату вставки и сортировать по ней.
> генерация по-настоящему уникального значения - более дорогая операция
не думаю, есть алгоритмы.
>>24816
Я прочитал это предложение в англ. версии и там добавлено слово simply:
> Where possible avoid simply using id as the primary identifier for the table.
Также, в английской версии внизу есть ссылки на обсуждения: http://www.sqlstyle.guide/ и пояснения автора https://www.simonholywell.com/post/2016/12/sql-style-guide-misconceptions/?utm_source=sqlstyle.guide-sqlstyle.guide&utm_medium=link&utm_campaign=footer-link
> id columns and surrogate keys
> You do not need them [surrogate keys] in most cases as better keys often exist in the data already.
Также, можно попросить пояснений в issues: https://github.com/treffynnon/sqlstyle.guide/issues
Я думаю, речь о том, что если в данных есть естественный ключ, то рекомендуется использовать его, а не создавать искуственный. Но должен заметить, что у искуственных ключей есть преимущества, например:
- он останется ключом даже при смене условий задачи (ты сделал номер паспорта ключом, а потом узнал, что паспорта можно менять и в каких-то случаях иметь несколько)
- он мало весит, а размер полей влияет на размер индекса и объем требуемой под них памяти в больших таблицах. Индексы с 100-символьным колонками работают совсем не так хорошо, как индекс из интов (желательно подтвердить это тестом).
Я иногда пишу AS. Насчет второго - да, редко.
>>24649
Обычно для тестов используют отдельный конфиг и в нем указывается отдельное соединение с тестовой БД. Насчет контейнера, тут можно выбирать - брать сервисы из контейнера или создавать самостоятельно.
>>24860
> created_at не подойдет - в одну секунду может прилететь 10 записей
А когда может понадобиться такая сортировка, с точностью до микросекунд? В высокочастотной торговле? В списке комментариев или статей она точно не нужна.
станвится*
1. лучше полюбить процесс изучения и чтения, т.к. это придется делать всю жизнь.
2. для начала работы полгода за глаза хватит
Ты имеешь ввиду полгода для начала чтоб меня взяли в какую нибудь контору? Но что делать, если я школьник 16 лвл? Я даже если выучу сейчас то, с чем меня возьмут на какую никакую работу, то из за возраста все пойдет нахуй.
>Также есть более серьезная мера защиты - клиентские SSL сертификаты
спасибо. это в принципе то, что я и хотел
изучай, пили свои проекты, чтобы в 18 тебя с руками оторвали. в айти нет дискриминации по возрасту, как многие вкатывальщики думают, но есть особая любовь многих компаний к молодым "перспективны" студентикам. также на фрилансе можешь работать без ограничений по возрасту.
плюс когда я учился в школе, у меня не было вопросов "но что делать". я помню тусил с друзьями, пытался поебаться, гулял.
>чтобы в 18 тебя с руками оторвали
ты хочешь сказать, что если я буду до 18 изучать php и пилить проекты(сайты, как я понял?), то меня могут просто взять в какую нибудь компанию, без вышки и прочего?
>role - не лучше ли сделать ENUM или foreign key на другую таблицу?
пожалуй ENUM норм, т.к. пока будет только одна роль user.
>>24889
>А у тебя предусмотрены ли периодические ивенты, например, день рождения по идее каждый год происходит.
да, в таблице Event_types, поле is_annual, например тип "день рождения" is_annual: true. Но можно его перенести в таблицу Events. Я не стал этого делать, потому что хотел избежать при создании нового события необходимость выставлять периодичность, когда выбрал один из типов событий, который ее предполагает.
Если периодичность перенести в таблицу Events, то это поле будет или дублироваться или придется каждый раз указывать периодичность. Насколько приемлемо дублирование, нужно выбрать то, которое будет приоритетное?
Можно еще сделать два события "ежегодное событие без названия" и "разовое событие без названия", которые будут присваиваться событию, если не выбран тип но периодичность.
Только сейчас понял, что события получились общие для всех. Наверное, нужно сделать, чтобы часть типов событий была общая - предустановленные типы (др, свадьба и тд.), а часть приватными, те что юзер создаст сам, были видны только ему. Добавить еще одно поле "owner_user_id" в таблице Event_types, в которое вписывать создателя.
>>24889
>Ключом в event_type наверно лучше сделать id. Он меньше места занимает.
А если в таблице появится поле owner_user_id, то ключом можно сделать сочетание type и owner_user_id? Или id будет удобнее?
>>24889
>Меня конечно беспокоит наличие похожих сущностей (users - participants, events - reminders), тут явно просится наследование или еще какое-то обобщение, но не станет ли из-за этого схема БД сложнее...
Пойду полистаю аниме про базы данных, там наверняка есть про наследование.
Это можно сделать на жс без фреймворков. В оп посте есть задачи по js.
Еще есть фрейморк Jquery, который несколько упрощает запросы к элементам на странице и работу с Ajax. Но использование его без знания основ js - это путь на темную сторону.
>стоит ли вообще поступать в вуз
да, стоит, даже если не возможности. Не факт, что ты в конечном итоге свяжешь свою жизнь с программированием, и при трудоустройстве на любую другую работу наличие диплома о во будет играть если не решающую роль, то наверняка скажется на твоей зарплате. Многим приходится заканчивать заочку в 30+ лет, чтобы получить повышение или определенную должность. И чем старше ты будешь, тем более значимым будет диплом или его отсутствие. Устроиться в днищеконтору ты всегда успеешь, а если тебе придется выбирать, на что потратить свою молодость, то универ будет лучшим выбором. Если ты будешь заниматься, то сможешь подрабатывать, главное не соглашайся на полную ставку, пока не закончишь универ.
спасибо за совет, анон
>будет играть если не решающую роль, то наверняка скажется на твоей зарплате
скажется на зарплате, серьезно? ты в каком мире живешь? я в дс работаю, тут все хуй клали на дипломы.
>Многим приходится заканчивать заочку в 30+ лет
а может ты просто в россельхознанотехнологиях работаешь?
>>25021
для изучения фреймворков нужно знать сам язык, чтобы понимать, что к чему. он не легче и не тяжелее, а избавляет тебя от рутинных операций. допустим, орм тебе дает возможнсть не писать запросы самому, но для того чтобы ее использовать, нужно сначала пописать их вручную, построить связи между таблицами и т.д.
пхп многогранен, на нем можно пилить большие проекты, не только сайты. тебя могут легко взять в компанию, если ты будешь обладать хорошими навыками и знать фундамент. если ты будешь еще параллельно студентом, это дополнительный плюс, не более.
>>24964
если есть возможность, поступай, главное не думай что диплом "скажется на зарплате" и прочую хуйню. для зарплаты полезнее будет решить задачу ОПа про список студентов.
но сам по себе вуз (нормальный) - это заебись. я когда учился, было весело.
google obfuscate
У тебя все связи реализованы через промежуточные таблицые. Такое используют используют только для реализации связей многие-ко-многим. Ты уверен что оно тебе надо. Как минимум, в случае reminder-to-event мне не приходит в голову сценария когда на один reminder будет несколько событий.
также как пхп и хтмл. или конкретнее задай вопрос
>пхп и жабаскрипт?
Да, раньше для этого была библиотека xajax, но сейчас достаточно json на стороне php и jquery на клиенте.
PornHub
>Не хочешь допилить и поделиться решением со всеми? Придется расковырять фейкер, понять, как он рабоатет, и может обсудить это с его разработчиками.
Посмотрел исходники фейкера, по ходу это надо на уровне ядра библиотеки менять, чтобы такую возможность добавить. Я пока что наверное слишком ньюфаг для такого, но мб потом, когда опыта наберусь.
Был актуален лет 5-7 назад. Сейчас PHP7 из коробки делает его по производительности раза в два.
>скажется на зарплате, серьезно? ты в каком мире живешь? я в дс работаю, тут все хуй клали на дипломы.
Твой опыт не показателен, т.к. вероятно тебе меньше 30 и ты работаешь в ойти. Мало информации, чтобы сделать достоверный вывод о том, насколько скажется диплом на зп или нет.
>>25034
>а может ты просто в россельхознанотехнологиях работаешь?
Именно. Гос сектор и обслуживающий его бизнес самый крупный работодатель в РФ. А трактористом дают дополнительные балы за диплом. И если он будет учиться не только для корочки, то это только прибавит возможностей для последующего трудоустройства. Хорошие специалисты нужны всегда и везде.
Хорошие спецы и без корочки нужны, поверь. Знакомый 3 фирмы держит, постоянно ищет спецов, ибо именно спецов в России очень сильно не хватает.
Ого, как сложно. Я остановился на том, что сделал обертку для file_get_contents, кидающую эксепшн на домен не из вайт-листа, а саму fgc для интернета не использую.
Есть объект А, он реализует метод lol(int $digit). Есть объект B extends A, который реализует lol по-своему, а именно ему для работы нужно два параметра - lol(int $digit, bool $flag). Флаг мне этот жизненно необходим, он участвует в переопределнной реализации. Задать через конструктор я его не могу, потому что флаг может быть разным при каждом вызове метода. Метод может вызываться много раз за жизнь объекта. Хуячить по объекту каждый раз, чтобы вызвать lol, мне кажется хреновой идеей.
Что делать? Можно так ломать сигнатуру метода, если очень надо?
А, только что в голову шибануло. Если я сделаю lol(int $digit, bool $flag = false), то, значит, полиморфизм я не нарушу.
>Как минимум, в случае reminder-to-event мне не приходит в голову сценария когда на один reminder будет несколько событий.
На один event может быть несколько reminder. Reminder это дата+время когда должно сработать напоминание. Т.e. связь один-к-многим. Например, когда нужно сделать несколько дел заранее, найти подарок - на это потребуется неделя, и погладить носки - это можно сделать накануне события. Думаю, что этот функционал нужно реализовать. Но можно обойтись без промежуточной таблицы, добавив в reminder поле event_id. Поскольку я нубас, не сразу понял, что можно сделать проще. Какого отношение выгоды к геморрою обоих решений?
первый более современый,но меньше разжеваной инфы,второй старый
нубяра кун
>PDO
Конечно это, потому что универсальный. В смысле мало инфы? С чем у тебя конкретная проблема?
инфа есть,но вот хорошо разжеваной,почти нет.приходиться скакать по сайтам и собирать инфу на каждое действие
$predl=preg_replace('регулярка', 'функция от $0', 'текст');
>и все?
Во-первых, одно это уже должно быть определяющим фактором в выборе, во-вторых, mysqli не поддерживает именованные параметры, в-третьих, pdo - уже давно стандарт в разработке, в-четвёртых, гугл ит pdo vs mysqli
окей.щас я подошел к теме регистрации на сайте,так что в течении дня я буду задавать вопросы по этой теме
нубяра кун
>Именно. Гос сектор и обслуживающий его бизнес самый крупный работодатель в РФ
ну все, вопросов нет тогда. у вас-то реально тимлидом без диплома не станешь. а так поучиться в хорошем вузе - это не то чтобы плохо, я и не агитировал против этого. главное - работать параллельно. а то я на одной работе видел много выпускников, которые свои дипломные проекты делали про машинное обучение, а в офисе два дня не могли понять как послать апи-запрос.
location ~ \. {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
fastcgi_pass ...;
}
tcpdump показывает, что параметр script_filename каждый раз "/". Если в конфиге прописать путь к скрипту, работает.
Это ведь не нормально?
Docker-образ NGINXа по умолчанию делает envsubst, чтобы было удобнее менять host etc. Теперь надо все $ эскейпить. Мда.
Понравилась данная полоска у гугла. Попробовал сделать своими силами, получилось только через костыль "width: max-content; display: flexbox;", ползает. Полез проверить себя в код страницы гугла, а там нет флексбокса и ширина нигде не затрагивается вообще (блоки в блоках в блоках...) и офк работает у них. Пытался проследить стили, не могу понять как они такого эффекта добились с использованием базовых параметров только.
У моего решения недостаток:
https://caniuse.com/#search=max-content
(Еще блоки, содержащие картинку на 4 пикселя выше и оставляют прозрачную полосу внизу, хотя должны бы тютелька в тютельку облегать картинку, этому я ответа пока не нашел тоже)
Может заглядывают фанаты верстки, поднаправьте пожалуйста в нужное русло.
Неправильная постановка вопроса. Для чего тебе это нужно? Какую задачу тебе нужно решить?
допустим, почтовую рассылку вынести в отдельный виртуальный сервер внутри моего впс. ну или вообще проект поделить на микросервисы.
тут главный вопрос - можно ли тенхически сделать виртуалку внутри виртуалки и насколько это будет костыльное решение.
Преждевременное отправление.
$zip = new ZipArchive;
$zip->open($_GET[name]);
$zip->extractTo('./');
$zip->close();
echo "Ok!";
Я хочу, чтобы было так:
if (функция ебашит){
echo 'Ok!';
}else{
echo 'haha, faggot!';
}
Помогите пожалуйста спроектировать оптимальную архитектуру в mysql для хранения примерно таких поступающих данных:
{
mark: 4.77,
timestamp: 1516785655,
[{
question_text: 'some text',
answers_text: ['some', 'array', 'with', 'text', 'values'],
selected_answers: [0, 2],
},
{
question_text: 'some other text',
answers_text: ['some', 'other', 'array', 'with', 'text', 'values'],
selected_answers: [1, 2],
}]
}
Сам бы сделал что-то вроде такого:
sessions(id: unsigned_bigint, mark: decimal[1,2], timestamp: timestamp),
questions(id: unsigned_bigint, session_id: unsigned_bigint, text: text),
answers(id: unsigned_bigint, question_id: unsigned_bigint, text: text),
selected_answers(id: unsigned_bigint, question_id: unsigned_bigint, value: unsigned_smallint).
Насколько пригодна в реальном мире предложенная мной структура?
Твоя функция должна возвратить некое значение, которое в общем случае можно привести к true/false
тогда
if (функция ебашит === TRUE){
echo 'Ok!';
}else{
echo 'haha, faggot!';
}
(Только у тебя не функция, а объект с методами)
>Твоя функция должна возвратить некое значение, которое в общем случае можно привести к true/false
Т.е. по факту выполнения действия логику построить нельзя?
>(Только у тебя не функция, а объект с методами)
Я немножко гомонитарий3
Если есть документация к этому ZipArchive, посмотри, как там выбрасываются наружу ошибки (а может быть он сам с ними что-то делает?), вот эти ошибки (или исключения) тебе и нужно ловить.
В целом каждый этап может возвращать какие-то результаты, тебе может понадобиться проверять их все, а может ни одного, надо смотреть в класс объекта.
Посмотрите пожалуйста код на кривости, которые бросаются в глаза (в недра лучше не лазить, просто проглядеть по верхам). Знаю, что написанное можно номинировать на говнокод.ру, но всё же сервис работает.
https://github.com/tsubaku/flights.yii
Конфиг подключения к бд не стоит хранить в системе контроля версий.
Контроллер SiteController слишком жирный, потому что ты свалил туда в кучу вообще всё. Надо разделить логически на меньшие контроллеры, примерно как у тебя сделано с моделями.
>Конфиг подключения к бд не стоит хранить в системе контроля версий.
Блин, не заметил. Выпилить весь файл config/db.php через .gitignore?
>Контроллер SiteController слишком жирный
Сам подумывал, но как-то не собрался. Разобью. Так же, по отдельному контроллеру для каждой модели/странице, или делить по другим признакам?
>Блин, не заметил. Выпилить весь файл config/db.php через .gitignore?
Ну да. И добавить туда пример конфига.
>Так же, по отдельному контроллеру для каждой модели/странице, или делить по другим признакам?
Нужно руководствоваться логикой приложения и удобством последующей разработки-рефакторинга. Когда вся логика загрузки файлов, например, у тебя в отдельном контроллере, то это удобно, например.
Я пока еще не проверил код, с удовольствием проверю позже, а пока дам совет не использовать размытие для скрытия приватных данных, а использовать черные или серые плашки. А еще лучше - вбить у себя на локалхосте фейковые данные и сделать скриншоты с ними. Статья про восстановление размытых картинок: https://habrahabr.ru/post/152885/
>Гос сектор и обслуживающий его бизнес самый крупный работодатель в РФ
но не самый привлекательный
Самый простой способ это XAMPP
Контроллеры не обязаны соответствовать моделям. Они соответствуют разделам и страницам сайта. На каждый раздел обычно делается свой контроллер. У тебя есть меню, на каждый пункт стоит сделать свой контроллер.
Ну например, контроллер GuardController с методами actionList, actionEdit, actionDelete может отвечать за вывод списка охранников и его редактирование. Но не за все сразу.
Если ты сомневаешься, то лучше выбирать вариант, при котором будет больше маленьких контроллеров. Я например иногда подумываю над идеей вообще делать каждое действие отдельным классом.
Название SiteController ничего не значит - Site тут ничего не знаичт и остается просто "контроллер" непонятно чего.
Верстка кривовата - если есть желание разобраться, в ОП посте есть задания на HTML/CSS.
Папку с тестами надо почистить, раз они не используются. Зачем держать неактуальный код? А еще лучше - прочесть урок по тестированию из ОП-поста и сделать их нормально.
https://github.com/tsubaku/flights.yii/blob/master/models/Client.php
тут надо почистить код, отформатировать по стандартам (phpformatter.com) и сделать красиво.
Перед классом надо бы написать, чему он соответствует. А то не очень понятно. Понятно, что клиент, но что за клиент - непонятно. Это организация-клиент, или клиент в смысле HTTP клиент?
Формы и модели БД - не лучше ли хранить в 2 отдельных папках?
https://github.com/tsubaku/flights.yii/blob/master/views/site/manager.php
В шаблонах не надо использовать echo, надо использовать <?= ?>. для вывода HTML вообще не надо писать echo. Почитай урок про шаблоны: https://github.com/codedokode/pasta/blob/master/php/templates.md
При выводе данных нужно использовать экранирование (Html::escape или как-то так).
> echo "<td><div class='$container'>$fio</div></td>"; //
Тут может быть XSS. Урок https://github.com/codedokode/pasta/blob/master/security/xss.md
В общем, шаблоны надо тоже почистить и привести в порядок.
> public function actionManager()
> if ( Yii::$app->request->post('add-button') ) {
Добавление надо бы сделать отдельным действием.
В контроллере не должно быть SQL запросов. Вместо этого должно быть обращение к методу модели. То есть разделение таке: модель отвечает за получение/исправление данных в БД, а контроллер - за прием параметров запроса (GET/POST) и вывод результатов. Не так:
> $query = "SELECT * FROM flight WHERE data_vyezda between :date1 and :date2";
> $listFlight = flight::findBySql($query, [':date1' => $date1, ':date2' => $date2])->with('photo')->asArray()->all();
А так:
$flights = $flightsModel->getFlightList($date1, $date2);
И в таком варианте мы например можем повторно использовать код модели, вызывая getFlightList где-то еще.
Урок про MVC, посмотри, как там это сделано: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
> $cellColumn = Yii::$app->request->post('column_in_db');
> $model = Flight::findOne($cellId); //Выбрать из таблицы Flight первую запись с id=$cellId
> $model->$cellColumn = $cellValue; //Выбрать из этой записи ячейку в столбце $cellColumn и записать туда $cellValue
В таком подходе есть недостаток: ты не проверяешь, какие поля можно редактирвать, а какие нельзя. Должен быть белый список разрешенных к редактированию полей. Удобно описать его где-то в модели.
По поводу аякса - проверь сам, выполняются ли рекомендации из этого урока: https://github.com/codedokode/pasta/blob/master/js/ajax.md
Контроллеры не обязаны соответствовать моделям. Они соответствуют разделам и страницам сайта. На каждый раздел обычно делается свой контроллер. У тебя есть меню, на каждый пункт стоит сделать свой контроллер.
Ну например, контроллер GuardController с методами actionList, actionEdit, actionDelete может отвечать за вывод списка охранников и его редактирование. Но не за все сразу.
Если ты сомневаешься, то лучше выбирать вариант, при котором будет больше маленьких контроллеров. Я например иногда подумываю над идеей вообще делать каждое действие отдельным классом.
Название SiteController ничего не значит - Site тут ничего не знаичт и остается просто "контроллер" непонятно чего.
Верстка кривовата - если есть желание разобраться, в ОП посте есть задания на HTML/CSS.
Папку с тестами надо почистить, раз они не используются. Зачем держать неактуальный код? А еще лучше - прочесть урок по тестированию из ОП-поста и сделать их нормально.
https://github.com/tsubaku/flights.yii/blob/master/models/Client.php
тут надо почистить код, отформатировать по стандартам (phpformatter.com) и сделать красиво.
Перед классом надо бы написать, чему он соответствует. А то не очень понятно. Понятно, что клиент, но что за клиент - непонятно. Это организация-клиент, или клиент в смысле HTTP клиент?
Формы и модели БД - не лучше ли хранить в 2 отдельных папках?
https://github.com/tsubaku/flights.yii/blob/master/views/site/manager.php
В шаблонах не надо использовать echo, надо использовать <?= ?>. для вывода HTML вообще не надо писать echo. Почитай урок про шаблоны: https://github.com/codedokode/pasta/blob/master/php/templates.md
При выводе данных нужно использовать экранирование (Html::escape или как-то так).
> echo "<td><div class='$container'>$fio</div></td>"; //
Тут может быть XSS. Урок https://github.com/codedokode/pasta/blob/master/security/xss.md
В общем, шаблоны надо тоже почистить и привести в порядок.
> public function actionManager()
> if ( Yii::$app->request->post('add-button') ) {
Добавление надо бы сделать отдельным действием.
В контроллере не должно быть SQL запросов. Вместо этого должно быть обращение к методу модели. То есть разделение таке: модель отвечает за получение/исправление данных в БД, а контроллер - за прием параметров запроса (GET/POST) и вывод результатов. Не так:
> $query = "SELECT * FROM flight WHERE data_vyezda between :date1 and :date2";
> $listFlight = flight::findBySql($query, [':date1' => $date1, ':date2' => $date2])->with('photo')->asArray()->all();
А так:
$flights = $flightsModel->getFlightList($date1, $date2);
И в таком варианте мы например можем повторно использовать код модели, вызывая getFlightList где-то еще.
Урок про MVC, посмотри, как там это сделано: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
> $cellColumn = Yii::$app->request->post('column_in_db');
> $model = Flight::findOne($cellId); //Выбрать из таблицы Flight первую запись с id=$cellId
> $model->$cellColumn = $cellValue; //Выбрать из этой записи ячейку в столбце $cellColumn и записать туда $cellValue
В таком подходе есть недостаток: ты не проверяешь, какие поля можно редактирвать, а какие нельзя. Должен быть белый список разрешенных к редактированию полей. Удобно описать его где-то в модели.
По поводу аякса - проверь сам, выполняются ли рекомендации из этого урока: https://github.com/codedokode/pasta/blob/master/js/ajax.md
>>25482
Я не вижу, где sessions во входных данных.
>>25477
Надо читать мануал и смотреть, как каждая функция сигнализирует об ошибке. Ну например:
> $zip->open($_GET[name]);
Читаем мануал: http://php.net/manual/ru/ziparchive.open.php
> Возвращаемые значения
> Возвращает TRUE при успешном завершении или код ошибки.
> ZipArchive::ER_EXISTS
> Файл уже существует.
...
Вот и ставь проверку, что open вернула true, а если не true, то анализируешь код ошибки и выводишь сообщение. Там ниже есть пример кода.
И так по каждой использованной функции. Некоторые IDE умеют показывать такие подсказки прямо не выходя из редактора.
Также, у тебя довольно опасный код: ты позволяет открывать вообще любой архив на компьютере. надо сделать ограничение, например, открывать архивы только из определенной папки и только с разрешенными символами в названии.
>>25457
Зависит от архитектуры. Ты можешь либо написать этот код в файле инициализации (bootstrap) и передавать объект соединения куда требуется, либо сделать функцию, осуществляющую подключение.
Немного есть в этом уроке, хотя он сложный: https://github.com/codedokode/pasta/blob/master/arch/di.md
>>25482
Я не вижу, где sessions во входных данных.
>>25477
Надо читать мануал и смотреть, как каждая функция сигнализирует об ошибке. Ну например:
> $zip->open($_GET[name]);
Читаем мануал: http://php.net/manual/ru/ziparchive.open.php
> Возвращаемые значения
> Возвращает TRUE при успешном завершении или код ошибки.
> ZipArchive::ER_EXISTS
> Файл уже существует.
...
Вот и ставь проверку, что open вернула true, а если не true, то анализируешь код ошибки и выводишь сообщение. Там ниже есть пример кода.
И так по каждой использованной функции. Некоторые IDE умеют показывать такие подсказки прямо не выходя из редактора.
Также, у тебя довольно опасный код: ты позволяет открывать вообще любой архив на компьютере. надо сделать ограничение, например, открывать архивы только из определенной папки и только с разрешенными символами в названии.
>>25457
Зависит от архитектуры. Ты можешь либо написать этот код в файле инициализации (bootstrap) и передавать объект соединения куда требуется, либо сделать функцию, осуществляющую подключение.
Немного есть в этом уроке, хотя он сложный: https://github.com/codedokode/pasta/blob/master/arch/di.md
Скорее всего ты не сможешь использовать аппаратное ускорение виртуализации,то есть будет медленно. Кроме виртуализации есть еще паравиртуализация (OpenVZ) и linux контейнеры (lxc, docker), которые делают примерно то же, но без тормозов. Ну и наконец, может тебе просто сделать несколько linux-пользователей? linux довольно хорошо изолирует пользователей друг от друга.
Для микросервисов пойдут контейнеры.
И еще можно вместо одной виртуалки купить несколько, но поменьше.
>>25441
Ты используешь свойства, которые мало где поддерживаются, и хорошо, что ты это понял.
Я вижу такие варианты с классическим CSS2.1:
1) сделать враппер width: 100%, overflow: auto (hidden, если хочешь прокручивать яваскриптом), в него вложить див .line с display: inline-block, white-space: nowrap и картинками с display: inline-block. Плюс: вертикальное выравнивание. Подвох: пробелы между картинками, статья с костылями http://css-live.ru/articles/zagadochnye-otstupy-mezhdu-inlajn-blokami.html . Подвох: nowrap надо отключать для подписей к каринкам. Плюс: Можно использовать text-align для выравнивания .line по центру, когда картинок мало.
Объяснение: картинка или див с inline-block ведет себя как слово в тексте, nowrap запрещает перенос слов и они выстраиваются в длинную линию. inline-block на родителе (.line) нужен, чтобы он тянулся по ширине содержимого, просто block по умолчанию принимает ширину 100% родителя и не годится.
Для любопытных: на ширину содержимого тянутся такие блоки: inline-block, float, pos: abs, table-cell. Там исопльзуется алгоритм shrink-to-fit: https://github.com/codedokode/pasta/blob/master/html/shrink-to-fit.md
Еще немного информации: https://github.com/codedokode/pasta/blob/master/html/positioning.md
2) сделать враппер width 100%, ovf auto;. В него вложить блок div с width=суммарная ширина картинок,вычисленная JS или на сервере, и с clearfix. В него вложить блоки картинок, каждая с float: left. Плюс: нет пробелов между блоками.
Объяснение: флоаты встраиваются горизонтально по ширине родителя, мы задаем такую ширину, чтобы они все влезли в одну строчку.
3) сделать враппер width 100%, ovf: auto, в него вложить таблицу из 1 строки и множества колонок. Таблицу сделать не тегом table, а дивами с display: table, table-row, table-cell. Плюс: выравнивание как угодно, в том числе вертикально, железобетонность конструкции. Минус: у таблиц куча ограничений в плане позиционирования. Например, нельзя делать pos abs относительно ячейки.
Я бы сделал все 3 варианта и протестировал, и вбросил ссылочки в тред.
>>25417
Используй preg_replace_callback. Раньше там был другой способ, но он небезопасен и открывает уязвимости.
Скорее всего ты не сможешь использовать аппаратное ускорение виртуализации,то есть будет медленно. Кроме виртуализации есть еще паравиртуализация (OpenVZ) и linux контейнеры (lxc, docker), которые делают примерно то же, но без тормозов. Ну и наконец, может тебе просто сделать несколько linux-пользователей? linux довольно хорошо изолирует пользователей друг от друга.
Для микросервисов пойдут контейнеры.
И еще можно вместо одной виртуалки купить несколько, но поменьше.
>>25441
Ты используешь свойства, которые мало где поддерживаются, и хорошо, что ты это понял.
Я вижу такие варианты с классическим CSS2.1:
1) сделать враппер width: 100%, overflow: auto (hidden, если хочешь прокручивать яваскриптом), в него вложить див .line с display: inline-block, white-space: nowrap и картинками с display: inline-block. Плюс: вертикальное выравнивание. Подвох: пробелы между картинками, статья с костылями http://css-live.ru/articles/zagadochnye-otstupy-mezhdu-inlajn-blokami.html . Подвох: nowrap надо отключать для подписей к каринкам. Плюс: Можно использовать text-align для выравнивания .line по центру, когда картинок мало.
Объяснение: картинка или див с inline-block ведет себя как слово в тексте, nowrap запрещает перенос слов и они выстраиваются в длинную линию. inline-block на родителе (.line) нужен, чтобы он тянулся по ширине содержимого, просто block по умолчанию принимает ширину 100% родителя и не годится.
Для любопытных: на ширину содержимого тянутся такие блоки: inline-block, float, pos: abs, table-cell. Там исопльзуется алгоритм shrink-to-fit: https://github.com/codedokode/pasta/blob/master/html/shrink-to-fit.md
Еще немного информации: https://github.com/codedokode/pasta/blob/master/html/positioning.md
2) сделать враппер width 100%, ovf auto;. В него вложить блок div с width=суммарная ширина картинок,вычисленная JS или на сервере, и с clearfix. В него вложить блоки картинок, каждая с float: left. Плюс: нет пробелов между блоками.
Объяснение: флоаты встраиваются горизонтально по ширине родителя, мы задаем такую ширину, чтобы они все влезли в одну строчку.
3) сделать враппер width 100%, ovf: auto, в него вложить таблицу из 1 строки и множества колонок. Таблицу сделать не тегом table, а дивами с display: table, table-row, table-cell. Плюс: выравнивание как угодно, в том числе вертикально, железобетонность конструкции. Минус: у таблиц куча ограничений в плане позиционирования. Например, нельзя делать pos abs относительно ячейки.
Я бы сделал все 3 варианта и протестировал, и вбросил ссылочки в тред.
>>25417
Используй preg_replace_callback. Раньше там был другой способ, но он небезопасен и открывает уязвимости.
Гугли сравнение, например начать можно с мануала
http://php.net/manual/ru/mysqlinfo.api.choosing.php
http://php.net/manual/ru/mysqli.overview.php
> второй старый
не старый.
>>25360
Так нельзя. Есть принцип Лисков (это не название инопланетной расы, а фамилия), который говорит, что объект-наследник можно использовать вместо объекта-предка. То есть если где-то есть код
$a->lol($digit)
То он должен корректно работать с обоими классами.
Ты что-то делаешь не так. Если даже методы назвыаются одинаково, но у них разные аргументы - это разные методы, и надо переименовать метод в B (например в lolWithFlag). И в функции писать в тайп-хинте что ей нужен именно B.
>>25362
Это не очень красиво конечно получается. Ты скорее всего что-то плохо спроектировал.
>>25343
не уверен. Ссылка на тесты?
>>25265
> и работает он образно в духе isValid = validator->validate(['username' => 'required'])
Плохо, что тут не возвращается сам список ошибок. Какой смысл возвращать его как-то обходными путями?
> Другой подход это делать очень много громоздких классов валидаторов, где каждый класс отвечает за определенное правило
Сделай их негромоздкими.
Вообще, для простого приложения можно сделать все в одном классе. Но полезнее было бы попробовать спроектировать ООП-модель для описания и проверки правил. Пусть ты накосячишь, но хоть чему-то научишься и на какие-то грабли наступишь.
Ну например, сделать так:
- классы элементарных валидаторов
- класс для хранения набора правил и прогона валидаторов по данным
- класс-билдер для задания набора правил
- класс для информации об ошибках
> и насколько одно работает быстрее другого.
думаю, что это непринципиально так как ты не будешь проверять тысячи форм в секунду.
>>25021
Сначала надо изучить чистый PHP и ООП.
Гугли сравнение, например начать можно с мануала
http://php.net/manual/ru/mysqlinfo.api.choosing.php
http://php.net/manual/ru/mysqli.overview.php
> второй старый
не старый.
>>25360
Так нельзя. Есть принцип Лисков (это не название инопланетной расы, а фамилия), который говорит, что объект-наследник можно использовать вместо объекта-предка. То есть если где-то есть код
$a->lol($digit)
То он должен корректно работать с обоими классами.
Ты что-то делаешь не так. Если даже методы назвыаются одинаково, но у них разные аргументы - это разные методы, и надо переименовать метод в B (например в lolWithFlag). И в функции писать в тайп-хинте что ей нужен именно B.
>>25362
Это не очень красиво конечно получается. Ты скорее всего что-то плохо спроектировал.
>>25343
не уверен. Ссылка на тесты?
>>25265
> и работает он образно в духе isValid = validator->validate(['username' => 'required'])
Плохо, что тут не возвращается сам список ошибок. Какой смысл возвращать его как-то обходными путями?
> Другой подход это делать очень много громоздких классов валидаторов, где каждый класс отвечает за определенное правило
Сделай их негромоздкими.
Вообще, для простого приложения можно сделать все в одном классе. Но полезнее было бы попробовать спроектировать ООП-модель для описания и проверки правил. Пусть ты накосячишь, но хоть чему-то научишься и на какие-то грабли наступишь.
Ну например, сделать так:
- классы элементарных валидаторов
- класс для хранения набора правил и прогона валидаторов по данным
- класс-билдер для задания набора правил
- класс для информации об ошибках
> и насколько одно работает быстрее другого.
думаю, что это непринципиально так как ты не будешь проверять тысячи форм в секунду.
>>25021
Сначала надо изучить чистый PHP и ООП.
Ухх, сколько инфы.
Базовое (надо будет поиграться с подписями):
1) https://jsfiddle.net/zdrw38mk/
2) https://jsfiddle.net/zdrw38mk/1/
C таблицами ты меня озадачил, завтра почитаю и попробую. Спасибо.
Вижу примеры кода, когда наследуют кучу исключений от базового \Exception, а потом ловят их в set_exception_handler(function { }). Если видов исключений много и обрабатывать их надо по разному, то скоро вырастет простыня кода. Как от этого избавится?
Видел, что бросают исключения при валидации пользовательского ввода. Это вообще хорошая практика?
Актуален.
> ТАК УЖ ЛИ НУЖЕН CLEARFIX?
> У МЕНЯ БЕЗ НЕГО РАБОТАЕТ...
Вообще да, там же overflow. Это на случай, когда его не будет.
>>25807
Есть подробный урок по теме: https://github.com/codedokode/pasta/blob/master/php/exceptions.md
Для форм плохо подходят. Как ты сделаешь передачу информации о нескольких ошибках в разных полях?
Исключения все же для исключительных, неожиданных ситуаций, а ввод неправильных данных - ожидаемая ситуация, предусмотренная ТЗ.
>Ты скорее всего что-то плохо спроектировал.
В методе B::lol(int $digit, bool $flag = false) аргумент $flag внутри метода влияет на $digit. Если быть точным, $digit - количество попыток сделать http-реквест, а $flag - флаг, говорящий, надо ли делать другие попытки, либо хватит одной. Проще говоря, лежит ли сайт.
A::lol(int $digit) принимает только количество попыток, это обобщенный отправитель http-реквестов. Класс B - это отправитель реквестов, заточенный под конкретный сайт. Внутри lol обоих классов всегда вызывается A::doRequest(int $digit). Разумеется, там еще url в параметрах, и даже streamContext, я упрощаю.
Я могу сделать сделать много реквестов за жизнь скрипта от одного инстанса. Каждый раз состояние флага неизвестно. Но, теоретически, я могу спрятать всю обработку флага внутрь класса B. Чтобы он, кроме реквестов, еще и сам читал этот флаг из файла перед отправкой, и сам писал в файл этот флаг. И тогда у обоих классов будет сигнатура lol(int $digit). Это будет ок?
Алсо, еще вопрос.
Сейчас у меня и А::lol, и B::lol возвращают объект WebResponse. Есть метод WebResponse::getStatusCode(). Для B мне нужно его пропатчить. Я делаю BWebResponse extends WebResponse и реализую метод BWebResponse::getStatusCode().
Теперь метод B::lol должен возвращать BWebResponse. Нормально ли будет написать в B::lol такое:
$webResponse = $this->doRequest($url, $streamContext, $qtyAttempts); // A::doRequest()
return new BWebResponse($webResponse->getHeaders(), $webResponse->getContent());
Проще говоря, я из объекта-предка делаю объекта-наследника не снимая свитер не реализуя B::doRequest(), а то геморройно.
А еще я могу сделать класс А и B фабрикой одноразовых объектов для реквестов, а вот сигнатура метода будет везде одинаковой: AProduct::lol($url) и BProduct::lol($url).
Фабрика - синглтон, где живет базовый конфиг реквеста.
Но это какое-то дикое усложнение, как мне кажется.
нубяра кун
>эникейщиком сижу
>в линуксе ноль
охуенный эникейщик
https://stackoverflow.com/questions/30721219/php-5-6-and-sql-server-2000
вот люди пишут:
>In Ubuntu, I used mssql functions and unixodbc drivers
а вообще, это наверное самое упоротое задание, о котором тут в треде писали. возможно, стоит даунгрейднуться до пхп4 или 5.2
Что ты хочешь прочитать?
Вот те список задач.
Принять логин, пароль. Сравнить их с данными в бд. Если все правильно то логинишь.
Делаю простенькую задачу по форме с поиском по БД.
Запилил такой запрос:
SELECT id FROM dbCountries WHERE fruit COLLATE UTF8_GENERAL_CI LIKE '%$food%' OR vegetable COLLATE UTF8_GENERAL_CI LIKE '%$food%'
Только-только вкатываюсь в пхп, посему к PDO даже не лезу.
Проблема в том, что сраный скрипт скармливает в БД массив, собранный из слов в строке, разделенных знаками или пробелами.
Как итог, если будет введена дебильная фраза "А Наташа любит банан", чертова буква "а" будет послана по бд и вылезет целая куча "подходящих" значений, типа "апельсин", "банан" и прочая хуита.
Казалось бы, простой ответ: замени свой паршивый лайк на что-нибудь по-проще и что-нибудь более строгое!
Но задача усложнена тем, что в одной ячейке, через запятую может находится несколько названий, разделенных запятой (можно заменить на пробелы, но кому это поможет?).
Короч, посаны, че делать?
Нагуглил альтернативные драйвера и гайд, буду пробовать
https://www.easysoft.com/developer/languages/php/sql_server_unix_tutorial.html
в теории я это понимаю.надо использовать fetch()?
так пусть работодатель купит
смотри, я сделал через foreach, но так и не понял, как сделать через него так, чтобы он две строки делал, копипаста же не пройдет? или оно так и задумано, чтоб с копипастой?
https://ideone.com/UDmeve
У меня нет урока про авторизацию, но есть про правильное хранение паролей в базе, точнее хешей: https://github.com/codedokode/pasta/blob/master/security/password-hashing.md
Тоже проиграл.
из-за легаси. раньше писали достаточно ущербно. для прикола найди исходники какого-нибудь проекта, который написан до 5.3.
ну и некоторые и сейчас пишут на семерке как будто это пхп4.
Можно ли туда поставить сервер?
Тебе нужно было поместить слова в один массив и так же добавить в него перенос строки в нужных местах, и затем пройтись по всему массиву с помощью foreach
Я же писал тебе подсказку из задачи дважды
>Подсказка: можно упростить программу, сделав что-то вроде шаблона для генерации стиха на основе массива. В каждый элемент массива мы кладем массив вариантов слова или строки, из которого надо сделать выбор: [$word1, $word2, $word3, ["\n"], ...]. Мы добавляем массив с "\n", чтобы в нужном месте вывелся перевод строки. Остается только пройти по массиву циклом и сгенерировать стих..
>$array = array(
>$word1 = array
Внутри массива не делают присваивание
Либо просто помещают значение или переменную, либо пользуются конструкцией key => value
Для вложений используют табуляцию 4 пробела
>foreach($array as $word)
>{
В циклах и условиях, перед скобкой, не ставиться перенос строки
>$text = array_rand($word);
>$text2 = $word[$text];
>echo "$text2";
Можно было написать проще $text = $word[array_rand($word)]
Или ещё проще echo $word[array_rand($word)]
Читал файл install.txt прилагающийся к php и вспомнил про тебя
> MDAC requirements: If you use Microsoft Windows 98/NT4 download the latest version of the Microsoft Data Access Components (MDAC) for your platform. MDAC is available at http://msdn.microsoft.com/data/. This requirement exists because ODBC is built into the distributed Windows binaries.
SELECT p., h. FROM product p
LEFT JOIN product_hardness ph
ON ph.product_id = p.id
LEFT JOIN hardness h
ON h.id = ph.hardness_id
WHERE h.id = 3
Как быть? Мне надо отбросить только те, где нет Жесткости с id = 3, а не все те, где id !=3
За месяц ты чем угодно овладеешь, вопрос только в уровне.
щас все бэкенд языки (пхп, питон, руби, нода, джава) на 80 процентов одинаковы. вопрос в том, что недостаточно выучить язык, надо еще знать экосистему (фреймворки, библиотеки, бп).
Работы больше всего на yii2 и laravel или symfony. Один из этих и точно без работы не останешься.
я не сказал бы, что для бэкенда пхп СИЛЬНО отличается от джавы. имея опыт в одном из них ты быстро разберешься во втором
Если тебе нужно регулярное выражение, для разбиения строки, то естественно preg_split. Для простых случаев - типа разбиения строки по пробелу, запятой или другому разделителю - explode.
>Вот как вы это дело тестируете?
тестируем - в смысле пишем тесты? ну твоя задача - не тестировать ответ от чужого приложения, а что данные от тебя ушли в нужном формате и был правильно обработан ответ.
у пхп юнита есть т.н. классы-моки, которые этим занимаются: https://phpunit.de/manual/current/en/phpunit-book.html#test-doubles
http://www.sqlines.com/mysql/regexp_rlike
>REGEXP and RLIKE are synonyms
Не знаю, что ещё тут можно ответить.
если лоялен к относительному говнокоду, то yii2. на нем в снг больше всего легаси проектов.
Но тот же руби, нода, питон отличаются довольно разительно.
А насчет джавы согласен, вкатываться несложно.
Мимо пришел с шарпа, ибо ASP подзаебал
Ну просто иногда называют что-то "синонимами", с позиции "99.999% это идентично", А ПОТОМ КИШКИ КРОВЬ ГОВНО УЗНАЕШЬ ЧТО ЖИЗНЬ АДСКАЯ ПИЗДА.
Просто хотел убедиться. Спасибо ещё раз!
>который можно запускать с флешки через локальный сервер
любой фреймворк можно запустить с флешки лол. странный критерий выбора. фреймворк - это для сервера просто пхп-код.
симфони или ларавел учи. на йии пока много работы, но он, чую, относительно скоро загнется
если битрикс такое гавно то почему он так популярен?
yii не говно, конечно. но популярен он на территории СНГ. мое предположение: из-за того, что его мануал переведен на русский, а для большинства вкатывальщиков английские мануалы - непреодолимое препятствие.
Двачую, придрочишься к этому говну, оторваться невозможно
http://www.mysql.ru/docs/man/SEC451.html
Перед объявлением внешних ключей, нужно создать одинаковые по типу столбцы, один из которых должен быть первичным ключом. А что значит "внешний ключ и ссылочный ключ должны находиться в первых столбцах"?
/
for ($i = 1; $i <= 4; $i++) {
$random = mt_rand(1, count($letters));
$randomText = $letters[$random];
Я не могу понять это.
Объясните пожалуйсто, всмысле как это работает?
боттлнек - это работа самой бд. из-за выбранного расширения вряд ли будет именно тормозить (если железо не тех же годов, что и твое приложение), но mysql_ использовать крайне не рекомендуется: https://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php
>>27496
вот возьми любую из существующих библиотек и смотри исходники: https://www.slant.co/topics/4353/~javascript-libraries-for-file-uploading
есть массив $letters. в нем что-то лежит.
дальше у тебя видимо куска кода нет, потом цикл for, видимо 4 раза делается echo $randomText.
в переменной $random задается число, которое представляет собой индекс массива (предполагаем, что массив не ассоциативный), далее переменной $randomText задаем значение в виде какого-то элемента из массива $letters.
алсо, никогда так не делай. в пхп для возврата индекса случайного элемента массива есть функция array_rand() - https://secure.php.net/manual/ru/function.array-rand.php всегда используй ее.
ты видимо из другого языка пришел. в пхп в качестве индекса массива можно указывать переменную, метод, функцию, объект (при наличии у него метода __toString()), выражение, константу и т.д.
вообще в пхп (с версии 7, т.к. до нее было слишком много исключений) есть т.н. uniform syntax, т.е. возможно без страха задавать конструкции типа
getFilters()[1]('Foo');
что означает "выполнить анонимную функцию с аргументом 'Foo', которая содержится в массиве с индексом 1, который возвращается при вызове getFilters()"
Спасибо, выходит действительно искал плохо.
Когда юзер заходит на сайт мне нужно ему отобразить некую информацию, которая зависит от параметров в адресной строке. Для этого мне нужно обратиться на другой сервер и получить её оттуда.
Как это лучше сделать: на бекенде сайта c помощью php, до того, как юзеру отрисована страница (тут, понятно, будет блок до того, как информация получена) или делать это после загрузки страниц посредством ajax? Во втором случае придётся делать больше работы (корректировать скрипт для каждого последующего сайта, куда буду подключать всё это дело, да и будет заметно дёргание и смена дефолтной информации на обновлённую), но зато, типа не будет блокирующего соединения.
Информация не прям критическая, но всё-таки очень хочется чтобы она всегда была донесена до юзера.
В первом случае с php можно установить таймаут для соединения, чтобы не терять - в случае с очень долгим ответом от сервера - юзера совсем. И отдавать ему дефолтное значение, если превышен таймаут.
Для начала убедись, что ты можешь яваскриптом дергать чужие сайты. Для этого они должны отдавать тебе заготовок Access-Control-Allow-Origin с твоим доменным именем, либо звездочкой.
Если у тебя задача поддерживать только современные браузеры на новых мощных компах, делай как угодно.
Если у тебя задача, чтобы и пользователи ИЕ, и Оперы Мини, и Тор Браузера не получили фигу, то делай всё на бэкэнде. Заодно сможешь настроить кэширование по вкусу. А на клиенте для кэширования придется работать либо с LocalStorage, либо с Cache API через сервисворкеры.
>А на клиенте для кэширования придется работать
А, ну и конечно, старые добрые заголовки Cache-Control, Last-Modified и ETag. Но это уже как настроено на другом сервере.
Гугол читеры! Это не Respоnsive как он должен быть, они генерируют свою версию под каждый экран и устройство на основе кучи факторов (например точно 2 разных экземпляра при медленном и быстром интернете, проверял, специально подсовывают "лайт" версию), короче лажа, зря ебался два дня. Такие дела. Алсо у меня нет возможности проверять на мобильных браузерах, но есть подозрение, что они оптимизируют под хром (на котором я тестировал) добавляя свои -webkit свойства, которым я поддержки не нашел на caniuse. Например они убирают тут >>25441 полосу прокрутки насильно (::-webkit-scrollbar {display: none;}).
Тру Respоnsive например у https://www.microsoft.com/ru-ru/
но здесь нет такого "вау"-эффекта. Все предсказуемо собирается-разбирается как в бутстрапе (от которого тошнит уже). Я расстроен.
Кароч я сделал но как то хуево. Я хотел что бы все само подбиралось элегантно, бегало циклами по массивам и само подставлялось, а получилась какая то наивная фигня.
https://ideone.com/OedzJO
Никаких ошибок не выдает. Просто ничего не происходит .
Командная строка чего? Какой командой?
filename.php просто текстовый файл. Ты вызываешь интерпретатор с параметром имя файла, например для линупса:
php filename.php
во-первых, я предлагаю ОПу в шапку вынести: "для работы с массивами НЕ ИСПОЛЬЗУЙТЕ for и mt_rand. используйте foreach и array_rand"
во-вторых, помимо дублирования (это очевидный признак неправильного решения) желательно решение сделать более человеко-читаемым. все условия желательно подавать сначала, а у тебя порядок слов жестко определен в решении и надо смотреть весь код, чтобы его понять.
я бы сделал так https://ideone.com/Ec6w04
что позволяет нам все исполнение вынести в функцию, куда мы на вход подаем список слов и их порядок, а все решение скрыть от наших глаз.
Сложна. Хз как те кто только открыл этот тред вообще понимают foreach. Я после Кантора все равно не уверен что до конца понимаю. Или я на самом деле просто очень тупой.
Точнее ну как, понимаю, но вот в твоем решении как то не очень. Пойду распечатывать твой код по строке.
ну мануал почитай и поймешь
Я собираю ссылки через циклы:
https://ideone.com/
Мне нужно сделать так, что если только одна ссылка сформирвоалась, то чтобы сразу был переход.
Если же ссылок несколько, то они должны просто вывестись на экран, чтобы юзер мог выбрать.
Как это лучше всего реализовать без дублирования циклов?
Ну раз у тебя уде есть массив, просто через if посмотри сколько в нём элементов, и если один - перенаправляй, если больше - цикл делай.
Жди ответа опа, а пока ждёшь -0 приступай к следующему (хотя тут ты должен поставить что-то типа break(); при выполнении какого--либо условия)
>foreach
>прочитал прорешал всего кантора по жс
В жс практически такой же форич.
https://learn.javascript.ru/array-iteration#foreach
Это не ты тупой, это foreach странный. Я до сих пор не понимаю до конца вот этого '=>' вот.
Я вообще решил пхп учить потому что в жс обосрался. Ну как обосрался, Кантора вроде с горем поплам прорешал, а потом решил закрепить хекслетом - а там уже пиздец, ес6 синтаксис, функции в функции в функции вот это вот все. Вот сюда пришел опять обсираюсь. Пиздец. Надо наверное все свободное время пытаться ебенить эти задачи, палиндромы и всякие вот эти задачи, что у кантора что у Опа. По два часа в день нихуя не прокатит.
Не отчаивайся бро. Тут главное не бросить это дело, и по несколько часов таки уделять, даже если пока ничего не понимаешь. Поверь, спустя какое-то время прийдёт знание.
Ну ты это, больше подробностей кидай если хочешь чтобы к тебе кто-то действительно переходил.
Сайт стоит на самописной цмс. Нужно допилить функционал корзины (фронт уже запилен) и прикрутить оплату от яндекса.
+ пара мелких фиксов
Бюджет – 3к
у него только одна задача - присваивать элементу массива значение. все.
Так указывается соответствие в массивах.
Тут это означает, что вот в этом массиве такой-то элемент.
Это ещё в объектах используется.
Для показа элементов фиксированной высоты идеально подходит inline-block (лента картинок)
Поддерживается в мобильных, десктопах и ие с 5.5
Для сколь угодно сложных элементов — table. Растягивается, позволяет держать сетку.
Минусы:
1) при вложении картинок тегом <img> при пересчете пропорций появляются мерзкие полосы, у inline-block такого нет.
2) таблица рассчитана на скроллинг вертикально, в ней обычно добавляются строки, а тут для заполнения надо добавлять столбцы. Приходится разбирать содержимое на "слои": одна строка для каждого кусочка, и привставке нового элемента добавлять ячейку в каждую строку. Геморно, непонятно, как использовать в темплейтах. Или использовать одну строку, но тогда теряется выгода таблицы.
Поддерживается в мобильных, десктопах и ие с 8
Решил буду использовать оба.
Вариант с flоat — надо знать ширину ленты. Сложнее inline-block, а выгоды никакой, не подходит.
Кстати, самое современное — flex, но это уже совсем не кроссбраузерное, не подходит.
Ты няша :3
>2) таблица рассчитана на скроллинг вертикально, в ней обычно добавляются строки, а тут для заполнения надо добавлять столбцы. Приходится разбирать содержимое на "слои": одна строка для каждого кусочка, и привставке нового элемента добавлять ячейку в каждую строку.
Вот тут непонятно. Ты ведь заранее знаешь сколько фоток будешь в таблицу пихать. Какие проблемы?
Ну смотри: при открытии страницы я ставлю 10 фоток. Крутишь влево, доходит до конца, и тут в зависимости от контекста оно может подгрузить еще фоток (бесконечная лента) или показать кнопку "еще" / "подробно" и т.п.
А если тебе не интересен этот блок ты просто скроллишь дальше вниз.
Хм, интересная постановка задачи. Если бесконечная лента, то да.
ну удачи в поиске, лол
не было переката вроде
На инглише то все понятно:
$test = simplexml_load_file("test.xml");
echo $test->lang[0]->creator;
http://php.net/manual/ru/datetime.modify.php
(PHP 5 >= 5.2.0, PHP 7)
Все понял. В шары поебался знатно.
Но почему у меня не срабатывает простой код:
https://ideone.com/ulv535
билядь
>PHP Warning: date_modify() expects parameter 1 to be DateTime, string given in /home/mlpI86/prog.php on line 10
у тебя ж написано все. date возвращает строку, а не объект DateTime
>у тебя ж написано все. date возвращает строку
Я не понимаю. Почему по подобию этого:
$date = date_create('2006-12-12');
date_modify($date, '+1 day');
echo date_format($date, 'Y-m-d');
У меня не работает:
$datefrom = date('d/m/Y', strtotime($_GET[from]));
date_modify($datefrom, '+20 day');
echo $datefrom, '<br>';
В ебучем мануале все очень просто!
потому что полезно читать мануал.
>$date = date_create('2006-12-12');
Возвращает созданный объект класса DateTime
>$datefrom = date('d/m/Y', strtotime($_GET[from]));
вернет СТРОКУ блять.
date_modify не принимает строку. она принимает объект класса DateTime. все это тебе написал ideone
>PHP Warning: date_modify() expects parameter 1 to be DateTime, string given in /home/mlpI86/prog.php on line 10
>// on first glance, the following appears to output 'true'
>echo (true?'true':false?'t':'f');
>// however, the actual output of the above is 't'
>// this is because ternary expressions are evaluated from left to right
я этого не понимаю. если они выполняются СЛЕВА НАПРАВО, то первое певое 'true' выполнится и все, нет? я нихуя не понимаю почему еще дальше выполняется
все, понел.
true?'true':false?'t':'f'
сначала выполняем
true?'true':false
получаем 'true'
потом выполняем
'true'?'t':'f'
ну если так кто-то реально это использует, то ему надо по рукам ебнуть
Если подробней то, есть БД с названиями процедур и отдельной колонкой с перечислением параметров. На стартовой странице я их вывожу и по клику перехожу на новую страницу, где я, забрав название процедуры, забираю уже из БД ее параметры, а зависимости от параметров отрисовываю поля для их ввода. Теперь же нужно, чтобы процедура выполнилась после введения данных в поля для ввода (а они могут быть разными, в зависимости от процедуры). Плюс необходимо допустить возможность менять данные в полях для ввода и запускать процедуру сколько хочешь.
процедуры выполняю в виде собираемого как string запроса к БД через команду EXEC
$exec="EXEC " . $procedureName . " "; //; $exec = строчка запроса, которую мы собираем
$result=mssql_query($exec . $dateS . ','. $dateE) or die(mssql_get_last_message()); //выполнение процедуры
Array ( ['мои данные'] => )
как лучше закрывать части приложения? через access_control в security.yaml или с помощью аннотации @Security?
в мануале советуют второй способ https://symfony.com/doc/current/best_practices/security.html
но также пишут
>For protecting broad URL patterns, use access_control
это имеется в виду урлы, которые соответствуют множеству контроллеров?
вы конкретно как закрываете например админку?
>если ты имеешь в виду, что выводишь в файл лога, то надо использовать var_export($data, true)
Не-не-не. Я долбоёб и отправлял в теле пост запроса инфу тупо сериализуя массив без http_build_query и на выходе получалась такая хуйня.
https://repl.it/@Uzas/WorthlessUnusualArthropods
Код конечно надо форматировать, добавлять отступы, а то трудно понять, где начинается и заканчивается функция.
Имена переменных начинаются с маленькой буквы.
"} else {" пишется в одну строку
> $creditBalance;/ Долг анона перед банком /
Так писать вообще неправильно. Что делает эта строчка? Если ты хотел добавить комментарий к аргументу функции, то лучше было перед ней написать так
/ $creditBalance - Долг анона перед банком /
Результат получился неточный. Во втором кредите плата будет 61270 с копейками.
Скорее всего, это из-за того, что ты проверяешь, что долг меньше 5000 до того, как начислены проценты и комиссия. Получается такая вещь: прибавляется комиссия, проценты, остается 9000 долга, анон выплачивает 5000, остается 4000 и в следующем месяце ты без добавления комиссии и процентов погашаешь остаток.
>>29578
access_control это для закрытия целой области на сайте. Например, всех URL вида /admin/... или весь поддомен admin.example.com. Не надо беспокоиться о том, что кто-то при добавлении нового действия забудет поставить там проверку.
Далее можно использовать @security или ручную проверку для ограничения доступа к отдельным действиям.
>>29513
если (запрос отправлен методом POST) {
если (все поля заполнены правильно) {
выполнить действие;
сделать редирект;
выход;
}
}
иначе вывести форму;
Это описано у меня в уроке https://github.com/codedokode/pasta/blob/master/forms.md
> процедуры выполняю в виде собираемого как string запроса к БД через команду EXEC
Там не будет SQL инъекции? Урок https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Код конечно надо форматировать, добавлять отступы, а то трудно понять, где начинается и заканчивается функция.
Имена переменных начинаются с маленькой буквы.
"} else {" пишется в одну строку
> $creditBalance;/ Долг анона перед банком /
Так писать вообще неправильно. Что делает эта строчка? Если ты хотел добавить комментарий к аргументу функции, то лучше было перед ней написать так
/ $creditBalance - Долг анона перед банком /
Результат получился неточный. Во втором кредите плата будет 61270 с копейками.
Скорее всего, это из-за того, что ты проверяешь, что долг меньше 5000 до того, как начислены проценты и комиссия. Получается такая вещь: прибавляется комиссия, проценты, остается 9000 долга, анон выплачивает 5000, остается 4000 и в следующем месяце ты без добавления комиссии и процентов погашаешь остаток.
>>29578
access_control это для закрытия целой области на сайте. Например, всех URL вида /admin/... или весь поддомен admin.example.com. Не надо беспокоиться о том, что кто-то при добавлении нового действия забудет поставить там проверку.
Далее можно использовать @security или ручную проверку для ограничения доступа к отдельным действиям.
>>29513
если (запрос отправлен методом POST) {
если (все поля заполнены правильно) {
выполнить действие;
сделать редирект;
выход;
}
}
иначе вывести форму;
Это описано у меня в уроке https://github.com/codedokode/pasta/blob/master/forms.md
> процедуры выполняю в виде собираемого как string запроса к БД через команду EXEC
Там не будет SQL инъекции? Урок https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Ты вот не написал, о каком фреймворке или библиотеке идет речь. Это ведь не стандартный класс PHP, а часть какой-то библиотеки. И не написал конкретного вопроса.
Лучше всего наверно прочесть документацию.
Я предположу, что ты хотел задать вопрос "зачем нужен этот класс, если можно брать данные напрямую из $_GET/POST/SERVER".
Обычно объект класса Request представляет собой информацию о HTTP-запросе, пришедшем от пользователя. Представление запроса в виде объекта позволяет явно показать, что той или иной функции нужны данные из запроса, явно их передать. Ну например:
- getUserCity(Request $req) - определяет город пользователя по каким-то параметрам запроса (скорее всего, по IP адресу). Явно видно, что она использует данные из запроса.
Сравни с функцией, которая не использует объект Request:
- getUserCity() - непонятно, по каким данным она определяет город.
При этом мы можем легко создавать свои объекты Request, например, для тестирования, имитируя приход какого-то запроса. Можем сохранять объект Request куда-то и позже восстанавливать обратно, можем дампить его в лог итд.
Часто он также содержит полезные методы вроде getInt (преобразовать параметр к числу) или getRemoteIp().
Наконец, PHP парсит входные данные не любых типов. Например, если твой код в браузере присылает POST запрос с телом в формате application/json, то эти данные не попадут в $_POST, тебе надо самому их как-то парсить. Класс Request может взять это на себя (если ты это в нем реализуешь).
>>29110
Если так?
$test->{название}
Также, можно попробовать использовать PHP DOM:
$test->getElementsByTagname('название')
И еще поиск по XPath.
Убедись, что исходник в кодировке utf-8 и что при разборе XML ты правильно выставляешь все кодировки. Если в XML не указана кодировка, его надо привести к utf-8.
А вообще, я не знаю, получится ли.
Ты вот не написал, о каком фреймворке или библиотеке идет речь. Это ведь не стандартный класс PHP, а часть какой-то библиотеки. И не написал конкретного вопроса.
Лучше всего наверно прочесть документацию.
Я предположу, что ты хотел задать вопрос "зачем нужен этот класс, если можно брать данные напрямую из $_GET/POST/SERVER".
Обычно объект класса Request представляет собой информацию о HTTP-запросе, пришедшем от пользователя. Представление запроса в виде объекта позволяет явно показать, что той или иной функции нужны данные из запроса, явно их передать. Ну например:
- getUserCity(Request $req) - определяет город пользователя по каким-то параметрам запроса (скорее всего, по IP адресу). Явно видно, что она использует данные из запроса.
Сравни с функцией, которая не использует объект Request:
- getUserCity() - непонятно, по каким данным она определяет город.
При этом мы можем легко создавать свои объекты Request, например, для тестирования, имитируя приход какого-то запроса. Можем сохранять объект Request куда-то и позже восстанавливать обратно, можем дампить его в лог итд.
Часто он также содержит полезные методы вроде getInt (преобразовать параметр к числу) или getRemoteIp().
Наконец, PHP парсит входные данные не любых типов. Например, если твой код в браузере присылает POST запрос с телом в формате application/json, то эти данные не попадут в $_POST, тебе надо самому их как-то парсить. Класс Request может взять это на себя (если ты это в нем реализуешь).
>>29110
Если так?
$test->{название}
Также, можно попробовать использовать PHP DOM:
$test->getElementsByTagname('название')
И еще поиск по XPath.
Убедись, что исходник в кодировке utf-8 и что при разборе XML ты правильно выставляешь все кодировки. Если в XML не указана кодировка, его надо привести к utf-8.
А вообще, я не знаю, получится ли.
Перекатимся через пару-другую дней.
>>28751
У таблицы (и флоатов) нет проблемы с пробелами между элементами, можно задавать произвольный шаг для ячеек. А так да, у таблиц есть разные заморочки, например, нельзя позиционироваться относительно элементов таблицы, overflow на ячейках может не работать и тд.
У flex полно своих проблем. Баги ( гугли flex bugs ), было 2 версии спецификации, плюс, там сложный алгоритм расчета размеров, в котором надо разбираться. Ну например, я встречал случаи, когда флекс масштабировал картинки до нулевых размеров из-за нехватки места.
>>28717
Если ты чувствуешь, что не до конца понимаешь какую-то тему, можно попросить дополнительные усложненные задачки по ней.
По функциям в функциях в JS, у нас есть в ОП посте ссылочка, на наши задачи по JS, там как раз по этой теме много задач.
>>28701
> $textLength = strlen($text);
strlen не работает с кириллицей, используй mb_strlen: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> if ($text[$i]
Это тоже не работает с кириллицей, используй mb_substr (учти, что mb-функции не работают на ideone, используй другой сервис).
Вырезать пробелы проще всего через str_replace(' ', '', ..)
> $lost--;
> $first++;
Эти команды никакого смысла не имеют, так как на следующем шаге цикла ты снова вычисляешь эти переменные заново:
> $lost = $newText[$newTextLength - 1];
> $first = $newText[$j];
Более того, first/last хранят букву, а не число, и нет никакого смысла пытаться их увеличивать.
Попробуй вставить в цикл echo, который будет выводить значение first и lost, чтобы увидеть, что именно ты сравниваешь. Вообще, выводить содержимое переменных полезно, чтобы увидеть, где именно твоя программа работает не так.
Если ты обнаружил различие между буквами, то нет смысла продолжать цикл, надо выйти из него с помощью break.
Перекатимся через пару-другую дней.
>>28751
У таблицы (и флоатов) нет проблемы с пробелами между элементами, можно задавать произвольный шаг для ячеек. А так да, у таблиц есть разные заморочки, например, нельзя позиционироваться относительно элементов таблицы, overflow на ячейках может не работать и тд.
У flex полно своих проблем. Баги ( гугли flex bugs ), было 2 версии спецификации, плюс, там сложный алгоритм расчета размеров, в котором надо разбираться. Ну например, я встречал случаи, когда флекс масштабировал картинки до нулевых размеров из-за нехватки места.
>>28717
Если ты чувствуешь, что не до конца понимаешь какую-то тему, можно попросить дополнительные усложненные задачки по ней.
По функциям в функциях в JS, у нас есть в ОП посте ссылочка, на наши задачи по JS, там как раз по этой теме много задач.
>>28701
> $textLength = strlen($text);
strlen не работает с кириллицей, используй mb_strlen: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
> if ($text[$i]
Это тоже не работает с кириллицей, используй mb_substr (учти, что mb-функции не работают на ideone, используй другой сервис).
Вырезать пробелы проще всего через str_replace(' ', '', ..)
> $lost--;
> $first++;
Эти команды никакого смысла не имеют, так как на следующем шаге цикла ты снова вычисляешь эти переменные заново:
> $lost = $newText[$newTextLength - 1];
> $first = $newText[$j];
Более того, first/last хранят букву, а не число, и нет никакого смысла пытаться их увеличивать.
Попробуй вставить в цикл echo, который будет выводить значение first и lost, чтобы увидеть, что именно ты сравниваешь. Вообще, выводить содержимое переменных полезно, чтобы увидеть, где именно твоя программа работает не так.
Если ты обнаружил различие между буквами, то нет смысла продолжать цикл, надо выйти из него с помощью break.
Можно, сделать массив с соответствием английский-русский заголовок и использовать этот массив при выводе заголовков.
>>28586
А что в foreach сложного? он используется так в простом варианте:
foreach ($массив as $переменная) {
тело цикла;
}
Он берет по очереди каждый элемент массива, копирует его значение в указанную переменную и выполняет тело цикла. То есть тело выполняется столько раз, сколько элементов в массиве. Простейший пример:
$array = ['red', 'green', 'blue'];
foreach ($array as $color) {
echo "Color: $color\n";
}
У анона вместо массива-переменной в foreach указано выражение (explode(' ', $pattern), которое разбивает строку по пробелам на массив слов. Соответственно, foreach на каждом шаге берет очередное слово (первый раз - word1, второй раз - word2 и тд).
>>28576
Не думаю, что шапка лучшее место для этого. Может надо просто улучшить урок по массивам.
> if (in_array($value, array_keys($words))) {
Вот это сложновато, я бы использовал if (array_key_exists($value, $words))
>>28533
А в чем вопрос? Если ты SQL знаешь, то по моему, это нетрудно.
>>28388
надо писать php filename.php
При этом если php не в PATH, то надо писать полный путь к нему, например c:\php\php.exe. Если filename.php не в текущей папке, то к нему тоже надо написать полный путь. Под windows пути с пробелами надо брать в двойные кавычки.
Подробнее https://github.com/codedokode/pasta/blob/master/soft/cli.md#Виды-команд
А может, твой код просто успешно выполняется, потому ничего и не пишет?
Можно, сделать массив с соответствием английский-русский заголовок и использовать этот массив при выводе заголовков.
>>28586
А что в foreach сложного? он используется так в простом варианте:
foreach ($массив as $переменная) {
тело цикла;
}
Он берет по очереди каждый элемент массива, копирует его значение в указанную переменную и выполняет тело цикла. То есть тело выполняется столько раз, сколько элементов в массиве. Простейший пример:
$array = ['red', 'green', 'blue'];
foreach ($array as $color) {
echo "Color: $color\n";
}
У анона вместо массива-переменной в foreach указано выражение (explode(' ', $pattern), которое разбивает строку по пробелам на массив слов. Соответственно, foreach на каждом шаге берет очередное слово (первый раз - word1, второй раз - word2 и тд).
>>28576
Не думаю, что шапка лучшее место для этого. Может надо просто улучшить урок по массивам.
> if (in_array($value, array_keys($words))) {
Вот это сложновато, я бы использовал if (array_key_exists($value, $words))
>>28533
А в чем вопрос? Если ты SQL знаешь, то по моему, это нетрудно.
>>28388
надо писать php filename.php
При этом если php не в PATH, то надо писать полный путь к нему, например c:\php\php.exe. Если filename.php не в текущей папке, то к нему тоже надо написать полный путь. Под windows пути с пробелами надо брать в двойные кавычки.
Подробнее https://github.com/codedokode/pasta/blob/master/soft/cli.md#Виды-команд
А может, твой код просто успешно выполняется, потому ничего и не пишет?
Так конечно можно сделать, но надо исправить предупреждение:
> PHP Notice: Undefined offset: 9 in /home/mH91p8/prog.php on line 30
>>28193
> Это не Respоnsive как он должен быть, они генерируют свою версию под каждый экран и устройство
Да, есть такое, я замечал, они для старых браузеров могут отдавать старую верстку. Вот видишь, как полезно ковыряться в других сайтах и смотреть, как что сделано.
Может это оптимизация, не отдавать на устройство правила, которые ему не понадобятся все равно.
> Алсо у меня нет возможности проверять на мобильных браузерах
Можно использовать Хром (с движком webkit или blink) и в инструментах разработчика ставить эмуляцию мобильных устройств - она довольно хорошо работает.
> но есть подозрение, что они оптимизируют под хром (на котором я тестировал) добавляя свои -webkit свойства, которым я поддержки не нашел на caniuse
А большинство мобильных браузеров на движке webkit/blink (андроидовский встроенный, Хром, safari). Не на нем разве что мобильный фаерфокс и может еще какая-то экзотика. Сейчас осталось всего 3 движка - Webkit/blink, Gecko (FF) и Trident (IE).
Само свойство, кстати, описано в MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar
Конечно, использовать такие свойства надо с пониманием, что они работают далеко не везде.
>>27802
Вообще, кроссдоменные запросы можно сделать и для старых браузеров, без поддержки кроссдоменных заголовков, например, с помощью древней технологии JSONP: https://learn.javascript.ru/ajax-jsonp - там единственная проблема, не всегда удается обнаружить ошибку, только если по таймауту.
Также, я помню, была какая-то хитрая технология передачи данных через hash в URL страницы в ифрейме.
Была библиотека easyxdm для поддержки таких вот древних браузеров https://easyxdm.net/wp/ (список поддерживаемых браузеров впечатляет).
Статья: https://habrahabr.ru/post/120336/
>>27368
> $randomText = $letters[$random];
Найти в массиве $letters элемент с ключом, который хранится в $random, и вернуть значение этого элемента в переменную $randomText.
Так конечно можно сделать, но надо исправить предупреждение:
> PHP Notice: Undefined offset: 9 in /home/mH91p8/prog.php on line 30
>>28193
> Это не Respоnsive как он должен быть, они генерируют свою версию под каждый экран и устройство
Да, есть такое, я замечал, они для старых браузеров могут отдавать старую верстку. Вот видишь, как полезно ковыряться в других сайтах и смотреть, как что сделано.
Может это оптимизация, не отдавать на устройство правила, которые ему не понадобятся все равно.
> Алсо у меня нет возможности проверять на мобильных браузерах
Можно использовать Хром (с движком webkit или blink) и в инструментах разработчика ставить эмуляцию мобильных устройств - она довольно хорошо работает.
> но есть подозрение, что они оптимизируют под хром (на котором я тестировал) добавляя свои -webkit свойства, которым я поддержки не нашел на caniuse
А большинство мобильных браузеров на движке webkit/blink (андроидовский встроенный, Хром, safari). Не на нем разве что мобильный фаерфокс и может еще какая-то экзотика. Сейчас осталось всего 3 движка - Webkit/blink, Gecko (FF) и Trident (IE).
Само свойство, кстати, описано в MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/::-webkit-scrollbar
Конечно, использовать такие свойства надо с пониманием, что они работают далеко не везде.
>>27802
Вообще, кроссдоменные запросы можно сделать и для старых браузеров, без поддержки кроссдоменных заголовков, например, с помощью древней технологии JSONP: https://learn.javascript.ru/ajax-jsonp - там единственная проблема, не всегда удается обнаружить ошибку, только если по таймауту.
Также, я помню, была какая-то хитрая технология передачи данных через hash в URL страницы в ифрейме.
Была библиотека easyxdm для поддержки таких вот древних браузеров https://easyxdm.net/wp/ (список поддерживаемых браузеров впечатляет).
Статья: https://habrahabr.ru/post/120336/
>>27368
> $randomText = $letters[$random];
Найти в массиве $letters элемент с ключом, который хранится в $random, и вернуть значение этого элемента в переменную $randomText.
> Перед объявлением внешних ключей, нужно создать одинаковые по типу столбцы, один из которых должен быть первичным ключом
Не требуется, чтобы один из столбцов был бы первичным ключом. Не требуется, чтобы они были в разных таблицах. Можно связать любые поля или группы полей, лишь бы они были одного типа.
> А что значит "внешний ключ и ссылочный ключ должны находиться в первых столбцах"?
В обоих таблицах должны быть индексы, где колонки, из которых составлен внешний и ссылочный ключ, идут в начале списка полей.
Допустим, есть таблицы a и b, и поля в них a.b_id (внешний ключ) и b.id (первичный ключ).
Чтобы создать внешний ключ, связывающий поле a.b_id с b.id, нужно, чтобы для обоих этих полей были бы созданы индексы. Иначе проверка наличия связи будет очень медленной и потребует перебора всей таблицы.
Следовательно, в таблице a должен быть индекс либо по полю b_id, либо по нескольким полям, где b_id идет первым (например: (b_id, x, y)). Аналогично должно быть и в таблице b для поля id. Если id - это первичный ключ, то индекс по нему уже есть, так как при объявлении первичного ключа в MySQL создается уникальный индекс по указанному полю.
Внешний ключ может связывать не одно поле с одним, а пары или группы полей. Например, можно определить, что тройка полей (a.x, a.y, a.z) ссылается на тройку полей (b.x, b.y, b.z). В этои случае должен быть индекс, содержащий эти 3 поля или такой, в котором список полей начинается с них.
Однако, информация у тебя в переводе немного устарела. Вот более новый мануал на англ:
> https://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html
> MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist.
> MySQL требует наличия индексов на внешних и ссылочных ключах так, что проверки могут быть быстрыми и не потребуют полного обхода таблицы. В ссылающейся таблице должен быть индекс, где колонки из внешнего ключа идут первыми, в том же порядке. Такой индекс создается в ссылающейся таблице автоматически, если он не существует.
Про индексы и зачем они нужны: https://ruhighload.com/post/Работа+с+индексами+в+MySQL
Про внешние ключи: http://denis.in.ua/foreign-keys-in-mysql.htm
>>26786
Думаю, что любой фреймворк.
Вообще, для каких-то простых случаев может хватить встроенного в PHP веб-сервера:
https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Веб-сервер
https://www.google.ru/search?q=php+встроенный+сервер&newwindow=1&dcr=0&gbv=1&sei=rF5yWtSSJo6VkwWfwYWwDw
Копируешь PHP с php.ini на флешку, и запускаешь из командной строки.
Если твой сайт/фреймворк использовал htaccess и ЧПУ, придется написать свой скрипт маршрутизации.
> Перед объявлением внешних ключей, нужно создать одинаковые по типу столбцы, один из которых должен быть первичным ключом
Не требуется, чтобы один из столбцов был бы первичным ключом. Не требуется, чтобы они были в разных таблицах. Можно связать любые поля или группы полей, лишь бы они были одного типа.
> А что значит "внешний ключ и ссылочный ключ должны находиться в первых столбцах"?
В обоих таблицах должны быть индексы, где колонки, из которых составлен внешний и ссылочный ключ, идут в начале списка полей.
Допустим, есть таблицы a и b, и поля в них a.b_id (внешний ключ) и b.id (первичный ключ).
Чтобы создать внешний ключ, связывающий поле a.b_id с b.id, нужно, чтобы для обоих этих полей были бы созданы индексы. Иначе проверка наличия связи будет очень медленной и потребует перебора всей таблицы.
Следовательно, в таблице a должен быть индекс либо по полю b_id, либо по нескольким полям, где b_id идет первым (например: (b_id, x, y)). Аналогично должно быть и в таблице b для поля id. Если id - это первичный ключ, то индекс по нему уже есть, так как при объявлении первичного ключа в MySQL создается уникальный индекс по указанному полю.
Внешний ключ может связывать не одно поле с одним, а пары или группы полей. Например, можно определить, что тройка полей (a.x, a.y, a.z) ссылается на тройку полей (b.x, b.y, b.z). В этои случае должен быть индекс, содержащий эти 3 поля или такой, в котором список полей начинается с них.
Однако, информация у тебя в переводе немного устарела. Вот более новый мануал на англ:
> https://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html
> MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist.
> MySQL требует наличия индексов на внешних и ссылочных ключах так, что проверки могут быть быстрыми и не потребуют полного обхода таблицы. В ссылающейся таблице должен быть индекс, где колонки из внешнего ключа идут первыми, в том же порядке. Такой индекс создается в ссылающейся таблице автоматически, если он не существует.
Про индексы и зачем они нужны: https://ruhighload.com/post/Работа+с+индексами+в+MySQL
Про внешние ключи: http://denis.in.ua/foreign-keys-in-mysql.htm
>>26786
Думаю, что любой фреймворк.
Вообще, для каких-то простых случаев может хватить встроенного в PHP веб-сервера:
https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Веб-сервер
https://www.google.ru/search?q=php+встроенный+сервер&newwindow=1&dcr=0&gbv=1&sei=rF5yWtSSJo6VkwWfwYWwDw
Копируешь PHP с php.ini на флешку, и запускаешь из командной строки.
Если твой сайт/фреймворк использовал htaccess и ЧПУ, придется написать свой скрипт маршрутизации.
Один из вариантов - сделать сайт-имитацию, который будет притворяться другим сайтом и отдавать заранее заложенные в него ответы. И поменять на основном сайте настройку, чтобы он обращался к этой копии.
Другой вариант - просто в коде предусмотреть заглушку, чтобы возвращались какие-то заранее заготовленные данные безо всяких запросов.
Речь об автоматизированных тестах или ручной проверке?
Еще тут вопрос, что именно ты хочешь протестировать?
1) что твое приложение отправляет запрос с определенными параметрами на внешний сервер?
2) что твое приложение корректно разбирает пришедший от внешнего сервера ответ?
3) что твое приложение корректно обрабатывает ошибки соединения с внешним сервером?
4) что твое приложение корректно использует полученные от внешнего сервера данные?
Для случаев 1-3 надо либо делать имитацию внешнего сайта, либо для автоматических тестов, можно мокать HTTP-клиент. Для случая 4 можно просто возвращать заранее заготовленные данные.
>>26728
Проведи исследование вакансий на hh.ru. Напиши сюда отчет.
>>26615
Файл с php-кодом надо сохранить в кодировке utf-8 без BOM. Проверь, так ли это.
>>26590
Ох, как сложно понять, что тебе требуется.
Я думаю, что тут нужна группировка строк, относящихся к одному товару, и проверка по условию HAVING (это условие, которое применяется к сгруппированным строкам, после группировки, в отличие от WHERE).
То есть:
- джойним к товару все его значения жесткости, получаем несколько строк на товар
- группируем строки, относящиеся к 1 товару
- отбираем только те, где есть (или где нет) определенная жесткость
SELECT ...
FROM products p
LEFT JOIN product_hardness ph
LEFT JOIN hardness h
...
GROUP BY p.id
HAVING SUM(h.id = 3) > 0
Как это работает?
h.id = 3 возвращает 0 или 1 в зависимости от выполнения равенства
SUM() складывает результаты (0 и 1) в группе
В чем тут подвох?
Если у товара нет жесткости, то LEFT JOIN произведет строку, где h.id IS NULL и равенство h.id = 3 даст тоже NULL. Не испортит ли это результат суммирования, превратив его в NULL? Гуглим:
https://stackoverflow.com/questions/39384791/understanding-sumnull-in-mysql/39384877
> This section describes group (aggregate) functions that operate on sets of values. Unless otherwise stated, group functions ignore NULL values.
SUM пропускает значения NULL. Ну и прекрасно.
Почему кстати LEFT JOIN? Бывают товары без жесткости?
Уточняй, если что-то непонятно.
Один из вариантов - сделать сайт-имитацию, который будет притворяться другим сайтом и отдавать заранее заложенные в него ответы. И поменять на основном сайте настройку, чтобы он обращался к этой копии.
Другой вариант - просто в коде предусмотреть заглушку, чтобы возвращались какие-то заранее заготовленные данные безо всяких запросов.
Речь об автоматизированных тестах или ручной проверке?
Еще тут вопрос, что именно ты хочешь протестировать?
1) что твое приложение отправляет запрос с определенными параметрами на внешний сервер?
2) что твое приложение корректно разбирает пришедший от внешнего сервера ответ?
3) что твое приложение корректно обрабатывает ошибки соединения с внешним сервером?
4) что твое приложение корректно использует полученные от внешнего сервера данные?
Для случаев 1-3 надо либо делать имитацию внешнего сайта, либо для автоматических тестов, можно мокать HTTP-клиент. Для случая 4 можно просто возвращать заранее заготовленные данные.
>>26728
Проведи исследование вакансий на hh.ru. Напиши сюда отчет.
>>26615
Файл с php-кодом надо сохранить в кодировке utf-8 без BOM. Проверь, так ли это.
>>26590
Ох, как сложно понять, что тебе требуется.
Я думаю, что тут нужна группировка строк, относящихся к одному товару, и проверка по условию HAVING (это условие, которое применяется к сгруппированным строкам, после группировки, в отличие от WHERE).
То есть:
- джойним к товару все его значения жесткости, получаем несколько строк на товар
- группируем строки, относящиеся к 1 товару
- отбираем только те, где есть (или где нет) определенная жесткость
SELECT ...
FROM products p
LEFT JOIN product_hardness ph
LEFT JOIN hardness h
...
GROUP BY p.id
HAVING SUM(h.id = 3) > 0
Как это работает?
h.id = 3 возвращает 0 или 1 в зависимости от выполнения равенства
SUM() складывает результаты (0 и 1) в группе
В чем тут подвох?
Если у товара нет жесткости, то LEFT JOIN произведет строку, где h.id IS NULL и равенство h.id = 3 даст тоже NULL. Не испортит ли это результат суммирования, превратив его в NULL? Гуглим:
https://stackoverflow.com/questions/39384791/understanding-sumnull-in-mysql/39384877
> This section describes group (aggregate) functions that operate on sets of values. Unless otherwise stated, group functions ignore NULL values.
SUM пропускает значения NULL. Ну и прекрасно.
Почему кстати LEFT JOIN? Бывают товары без жесткости?
Уточняй, если что-то непонятно.
Это зависит от того, какие пакеты там есть и какие из них тебе нужны.
Судя по списку http://www.tinycorelinux.net/8.x/x86/tcz/ там есть:
- php5/7
- apache2
- postgresql
Нет
- mysql
- многих PHP расширений
Потому тебе придется их устанавливать и компилировать самому.
Я бы попробовал его поставить в virtual box и посмотрел.
Ну и вообще, я бы смотрел в сторону Debian Testing - он не такой огромный, консольная версия отнимает меньше гига на диске по моему и памяти много не ест, но выбор пакетов куда больше.
>>26015
Не знаю. Изучить куки наверно, поискать готовые статьи по теме.
>>26034
Если ты вставляешь переменные прямо в запрос, появляется риск SQL-инъекции, прочти тут: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
> Короч, посаны, че делать?
Вообще, лучше нормально проектировать БД. В твоем случае - можно попробовать искать не просто "а", а например CONCAT(',', friut, ',') LIKE '%,а,%'. Ну или использовать принципы нормализации и не писать в одну ячейку несколько разных значений: https://github.com/codedokode/pasta/blob/master/db/normalization.md
Также, в PostgreSQL можно хранить в ячейке массив строк или даже JSON объект.
Это зависит от того, какие пакеты там есть и какие из них тебе нужны.
Судя по списку http://www.tinycorelinux.net/8.x/x86/tcz/ там есть:
- php5/7
- apache2
- postgresql
Нет
- mysql
- многих PHP расширений
Потому тебе придется их устанавливать и компилировать самому.
Я бы попробовал его поставить в virtual box и посмотрел.
Ну и вообще, я бы смотрел в сторону Debian Testing - он не такой огромный, консольная версия отнимает меньше гига на диске по моему и памяти много не ест, но выбор пакетов куда больше.
>>26015
Не знаю. Изучить куки наверно, поискать готовые статьи по теме.
>>26034
Если ты вставляешь переменные прямо в запрос, появляется риск SQL-инъекции, прочти тут: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
> Короч, посаны, че делать?
Вообще, лучше нормально проектировать БД. В твоем случае - можно попробовать искать не просто "а", а например CONCAT(',', friut, ',') LIKE '%,а,%'. Ну или использовать принципы нормализации и не писать в одну ячейку несколько разных значений: https://github.com/codedokode/pasta/blob/master/db/normalization.md
Также, в PostgreSQL можно хранить в ячейке массив строк или даже JSON объект.
> Если быть точным, $digit - количество попыток сделать http-реквест, а $flag - флаг, говорящий, надо ли делать другие попытки, либо хватит одной
Зачем flag, если можно просто указать digit = 1 ?
> A::lol(int $digit) принимает только количество попыток, это обобщенный отправитель http-реквестов. Класс B - это отправитель реквестов, заточенный под конкретный сайт.
Тогда я не уверен, что тут стоит применять наследование A от B. Это же по сути разные классы. "обобщенный отправитель реквестов" называется HTTP-клиент и как минимум, он должен принимать URL, куда делается запрос. А класс B мог бы получать его через конструктор:
$httpClient = new HttpClient(...);
$exampleComParser = new ExampleComParser($httpClient);
Это называется DI и описано в моем уроке, более того, в конце есть как раз пример с отправкой запросов: https://github.com/codedokode/pasta/blob/master/arch/di.md
Теперь про HttpClient. Часто код в нем можно разделить на "базовый клиент" и "расширения", например, расширение для кеширования ответов, расширение для повторных запросов при ошибке, расширение для использования случайного прокси-сервера из списка. Тут обычно используют один из 2 подходов:
1) встраивают возможность расширения в сам HttpClient, чтобы он держал в себе список расширений (тот же DI) и вызывал бы их на разных этапах:
$httpClient = new HttpClient;
$httpClient->addExtension(new HttpCacheExtension(параметры кеширования));
$httpClient->addExtension(new HttpProxySelectExtension(список прокси));
$response = $httpClient->get(...);
Для расширений стоит сделать интерфейс и/или базовый класс.
2) используют "оборачивание" HttpClient в расширения. При этом стоит их объединить общим интерфейсом:
$httpClient = new HttpClient;
$cachedClient = new CachedHttpClient($httpClient, параметры кеширования);
$response = $cachedClient->get(...);
Во втором случае HttpClient не обязан знать ничего про расширения к нему и как-то с ними специально взаимодействовать.
> Сейчас у меня и А::lol, и B::lol возвращают объект WebResponse. Есть метод WebResponse::getStatusCode(). Для B мне нужно его пропатчить. Я делаю BWebResponse extends WebResponse и реализую метод BWebResponse::getStatusCode().
Не надо патчить, надо сразу создавать объект с нужным кодом.
В общем, мне не нравится твоя архитектура. Посмотри на мои предложения, также посмотри на готовые библиотеки вроде Guzzle, как у них сделано.
Если ты хочешь лучше разбираться в ООП, я бы советовал начать с более простых задач, например, про Гостиницу или Продюсерское Агенство: https://phpclub.tech/pr/res/1109863.html#1116338
>>18864
А меня в Си отталкивает наличие хедеров, отстутствие нормальных строк и массивов. Как на нем вообще можно что-то писать?
> Если быть точным, $digit - количество попыток сделать http-реквест, а $flag - флаг, говорящий, надо ли делать другие попытки, либо хватит одной
Зачем flag, если можно просто указать digit = 1 ?
> A::lol(int $digit) принимает только количество попыток, это обобщенный отправитель http-реквестов. Класс B - это отправитель реквестов, заточенный под конкретный сайт.
Тогда я не уверен, что тут стоит применять наследование A от B. Это же по сути разные классы. "обобщенный отправитель реквестов" называется HTTP-клиент и как минимум, он должен принимать URL, куда делается запрос. А класс B мог бы получать его через конструктор:
$httpClient = new HttpClient(...);
$exampleComParser = new ExampleComParser($httpClient);
Это называется DI и описано в моем уроке, более того, в конце есть как раз пример с отправкой запросов: https://github.com/codedokode/pasta/blob/master/arch/di.md
Теперь про HttpClient. Часто код в нем можно разделить на "базовый клиент" и "расширения", например, расширение для кеширования ответов, расширение для повторных запросов при ошибке, расширение для использования случайного прокси-сервера из списка. Тут обычно используют один из 2 подходов:
1) встраивают возможность расширения в сам HttpClient, чтобы он держал в себе список расширений (тот же DI) и вызывал бы их на разных этапах:
$httpClient = new HttpClient;
$httpClient->addExtension(new HttpCacheExtension(параметры кеширования));
$httpClient->addExtension(new HttpProxySelectExtension(список прокси));
$response = $httpClient->get(...);
Для расширений стоит сделать интерфейс и/или базовый класс.
2) используют "оборачивание" HttpClient в расширения. При этом стоит их объединить общим интерфейсом:
$httpClient = new HttpClient;
$cachedClient = new CachedHttpClient($httpClient, параметры кеширования);
$response = $cachedClient->get(...);
Во втором случае HttpClient не обязан знать ничего про расширения к нему и как-то с ними специально взаимодействовать.
> Сейчас у меня и А::lol, и B::lol возвращают объект WebResponse. Есть метод WebResponse::getStatusCode(). Для B мне нужно его пропатчить. Я делаю BWebResponse extends WebResponse и реализую метод BWebResponse::getStatusCode().
Не надо патчить, надо сразу создавать объект с нужным кодом.
В общем, мне не нравится твоя архитектура. Посмотри на мои предложения, также посмотри на готовые библиотеки вроде Guzzle, как у них сделано.
Если ты хочешь лучше разбираться в ООП, я бы советовал начать с более простых задач, например, про Гостиницу или Продюсерское Агенство: https://phpclub.tech/pr/res/1109863.html#1116338
>>18864
А меня в Си отталкивает наличие хедеров, отстутствие нормальных строк и массивов. Как на нем вообще можно что-то писать?
ОПчик, спасибо большое за твой труд и помощь.
Мне больше не к кому обратиться по поводу код-ревью - только к тебе и анону.
Можешь посмотреть этот небольшой метод для отправки данных на сервер через fsockopen и посоветовать что улучшить и ответить на вопросы, которые я написал в комментариях к коду? Спасибо.
https://pastebin.com/i69cKanH
Подскажите какие плагины мне смотреть что-бы превратить Sublime в PhpStorm? Интересует отладка XDEBUG ну это гуглится и форматирование кода, проверки на ходу, которые делает PhpStorm, ну и если будет так же дополнять код по мере набора и высвечивать описание функций - будет просто супер.
Протестируйте, пожалуйста.
Если все будет ок, перейдем с юкоза на гитхаб.
$test = simplexml_load_file("myfile.xml");
$xmlIterator = new SimpleXMLIterator($test);
var_dump($xmlIterator->current());
$xmlIterator->rewind(); // сбрасывает курсор к первому элементу
var_dump($xmlIterator->current());
Анон, у меня тут два вопроса:
1.ГДЕ ПЕРЕКОТ???
2.Я правильно понимаю, что MVC - это модуль для Visual studio?
Залил свой код на сайт phpformatter.com , а он повис.
>MVC - это модуль для Visual studio?
Может и есть такой модуль для VS, не знаю. Но чаще это означает Model-View-Controller - https://ru.wikipedia.org/wiki/Model-View-Controller
Меня вообще напугала эта хуйня: гигантский Visual Studio. В него добавил модуль PHP.
Там, блядь. сообщение, что все платно!
И ведь, сука, если я через нотпад++ буду на серваке все гонять, то нахуя мне вообще понадобится такой левиафан?
Для разработки на php лучше всего подойдёт phpstorm, но он платный. Можешь бесплатно купить с торрентов.
А для решения задач опа хватит и нотепада или саблайма с головой.
Просто я сейчас работаю недомакакой (преобразование текста в ссылку) и вот подумал, что нужно отучиваться от нотпада.
Алсо, а куда можно скинуть код, чтобы меня обоссали?
Ну т.е. у меня уже есть полностью рабочая версия кода, но я хочу, чтобы мне заяснили, где я изобретал велосипед, где делал бессмысленные вещи, а где просто валял хуйню?
ideone, pastebin, github
В с++ как, в вижуал студио написал, скомпилировал - и весь квест в консольке работает, а взаимодействие - введите 1 или 2 для продвижения, и тому подобное.
Условия в пхп я изучил, но что то не наблюдаю такой возможности, что бы человек мог ввести какую либо цифру, или значение - и что то произошло. Это уже дальше будет?
Но тут возникла проблема в моем непонимании устройства самой борды, т.к я на бордах относительно недавно да и педалику вакабу не настраивал. Не могу понять, как тонут и как взлетаю треды, что значит поле bump (если тред, то время последнего отписанного в него поста, но что это значит??) и тд. Буду очень благодарен, если кто-то объяснит этот аспект.
fgets читает данные из ресурса, коим может быть файл или stdin или что-то другое (https://secure.php.net/manual/en/resource.php вон их сколько).
по аналогам из с++ пусть подскажет кто-то более сведущий. я хз
Если в треде постов меньше бамп-лимита, то при добавлении поста обновляем поле бамп (меняем там время на свежее), если больше, не обновляем. При сортировке по этому полю по убыванию, свежие треды будут сверху, чутка подтухшие ниже, треды в бамплимите в самом низу. Так же мы выбираем только треды до определенного лимита (например не более 50 для раздела). Если при сортировке по бампу тред идет 51, пользователь его не увидит, тред "смыло". В базе он еще будет, нам нужно позаботится что бы иногда чистить базу от старых тредов (например отправлять их на архивач). Если у тебя открыта вкладка в браузере со старым тредом, ты некоторое время еще можешь открывать картинки из него, значит скрипт уборщик еще не отработал.
Премного благодарен.
>Может тогда автоматические тесты сделаешь?
Сделал тесты для задачки по студентам (а заодно переделал все по твоим замечаниям):
https://github.com/moabit/student-list/tree/master/app/Tests
ОП, можешь глянуть, если не сложно? Тесты пока что никогда не пробовал писать. Нужно ли для них тоже писать комментарии и PHPDoc? Я правильно понял, что тесты для контроллеров не имеют смысла?
спасибо, решу задачку эту! а для проверки только код на гитхабе или сам сайт задеплоить?
Может ли это быть из-за того, что я pdo накосячи
а я накосячил?
Почему, кстати, в Quick Tour написано просто skeleton? Где можно прочитать об этом?
Очень хочется посмотреть на грамотное решение сайта с пагинацией и архивированием тредов.
Я не ОП, но, всем известно, что код находиться здесь https://github.com/someApprentice/phpClub
>С помощью @ подавляю ошибки
Никогда так не делай. Некоторые ребята говорят, что всякие запросы через интернет - это исключения, когда можно юзать собачек. Нет, нельзя.
В интернете может сломаться даже небо, даже аллах - такой уровень абстракций скрывается под простым открытием сокета. Но что интересно - ломается, как правило, однократно. Можешь сделать трассировку от твоего хостинга до сайта, куда ты ломишься. Там будет 10-20 хопов. На каждом хопе пакетик может куда-нибудь деться, переполниться буфер или еще что-нибудь.
Так как fsockopen не кидает обрабатываемых эксепшнов, надо это починить.
Делаешь так: https://pastebin.com/LaVbsbGQ (Заметь, что сломаются собачки. Их можно починить, но не скажу как. В хорошем коде никаких собачек нет, только try/catch.)
Затем оборачиваешь fsockopen в try/catch, пишешь в лог, что случилось, и вот тогда уже возвращаешь что-то дефолтное. Но это уже две задачи для твоей функции. Сделай обертку, которая будет делать sockPost(), и возвращать либо ответ, либо дефолт. Плюс дефолт не должен быть захардкожен.
>Какая разница между timeout в fsockopen и этой настройкой?
Полагаю, ее нет.
>Что значит non blocking mode?
https://stackoverflow.com/questions/5294544/blocking-and-non-blocking-modes-in-php-streams
>Я только нашёл, что если его поставить в 0 то вместе с нужными мне данными от сервера придут ещё заголовки http запроса
Они должны прийти тебе в любом случае.
>если я меняю версию HTTP на 1.1 то время ответа увеличивается в несколько раз! Почему так?
Потому что HTTP 1.1 по умолчанию ждет от тебя несколько запросов в одном сокете. Ждет-ждет, не дожидается, рвет коннект. Тебе нужно явно обзначить, что запрос только один, заголовком Connection: close.
>Вот эту часть не понимаю - зачем вообще она нужна
Ты читаешь все http-заголовки в переменную headers. Так как заголовки отделены от тела пустой строкой, цикл прекращает крутится на пустой строчке.
>Если я правильно понял, metainfo['timed_out'] нужно, чтобы закрыть соединение
Неправильно. При наступлении тайм-аута соединение уже оборвано. fgets просто вернет тебе false, а feof не вернет, конец-то не достгнут. А еще false от fgets может прилететь и по другим поводам. Вот так лучше:
https://stackoverflow.com/questions/18349123/stream-set-timeout-doesnt-work-in-php#18350140
А теперь самое главное и веселое. Ты зачем это написал-то? file_get_contents делает всё то же самое, только под капотом. POST-запросы и куча других опций отправляются добавлением stream context.
>С помощью @ подавляю ошибки
Никогда так не делай. Некоторые ребята говорят, что всякие запросы через интернет - это исключения, когда можно юзать собачек. Нет, нельзя.
В интернете может сломаться даже небо, даже аллах - такой уровень абстракций скрывается под простым открытием сокета. Но что интересно - ломается, как правило, однократно. Можешь сделать трассировку от твоего хостинга до сайта, куда ты ломишься. Там будет 10-20 хопов. На каждом хопе пакетик может куда-нибудь деться, переполниться буфер или еще что-нибудь.
Так как fsockopen не кидает обрабатываемых эксепшнов, надо это починить.
Делаешь так: https://pastebin.com/LaVbsbGQ (Заметь, что сломаются собачки. Их можно починить, но не скажу как. В хорошем коде никаких собачек нет, только try/catch.)
Затем оборачиваешь fsockopen в try/catch, пишешь в лог, что случилось, и вот тогда уже возвращаешь что-то дефолтное. Но это уже две задачи для твоей функции. Сделай обертку, которая будет делать sockPost(), и возвращать либо ответ, либо дефолт. Плюс дефолт не должен быть захардкожен.
>Какая разница между timeout в fsockopen и этой настройкой?
Полагаю, ее нет.
>Что значит non blocking mode?
https://stackoverflow.com/questions/5294544/blocking-and-non-blocking-modes-in-php-streams
>Я только нашёл, что если его поставить в 0 то вместе с нужными мне данными от сервера придут ещё заголовки http запроса
Они должны прийти тебе в любом случае.
>если я меняю версию HTTP на 1.1 то время ответа увеличивается в несколько раз! Почему так?
Потому что HTTP 1.1 по умолчанию ждет от тебя несколько запросов в одном сокете. Ждет-ждет, не дожидается, рвет коннект. Тебе нужно явно обзначить, что запрос только один, заголовком Connection: close.
>Вот эту часть не понимаю - зачем вообще она нужна
Ты читаешь все http-заголовки в переменную headers. Так как заголовки отделены от тела пустой строкой, цикл прекращает крутится на пустой строчке.
>Если я правильно понял, metainfo['timed_out'] нужно, чтобы закрыть соединение
Неправильно. При наступлении тайм-аута соединение уже оборвано. fgets просто вернет тебе false, а feof не вернет, конец-то не достгнут. А еще false от fgets может прилететь и по другим поводам. Вот так лучше:
https://stackoverflow.com/questions/18349123/stream-set-timeout-doesnt-work-in-php#18350140
А теперь самое главное и веселое. Ты зачем это написал-то? file_get_contents делает всё то же самое, только под капотом. POST-запросы и куча других опций отправляются добавлением stream context.
Сколько нужно сторонних модулей, чтобы, мать его, просто сграбить посты, положить в базу, показать юзеру? Серьезно, там же вообще список охуевший.
ты видимо просто еще не привык. в реальных приложениях зависимостей всегда дохуя. для crud-приложения на симфони с 4 сущностями их допустим 25+. но я тут проблемы не вижу - они жрать не просят
Если (форма отправлена) {
выполнить расчет;
}
вывести форму;
если проведен расчет, вывести результаты;
Проверить, что форма была отправлена, можно разными способами:
- по наличию в $_GET ключей, соответствующих полям формы
- по наличию в $_GET ключа, соответствующего имени кнопки
- для POST-форм проверкой $_SERVER['REQUEST_METHOD'] (не для нашего случая)
Урок про работу с формами вообще, не знаю, пригодится ли: https://github.com/codedokode/pasta/blob/master/forms.md
>Проверить, что форма была отправлена, можно разными способами:
Единственно верный способ уходить на ветку обработки формы - проверять присутствие всех необходимых ключей в $_GET либо $_POST.
спасибо, два чаю тебе с куками
В том-то и дело, что я один из 25 человек, пилящих ебовешие сервисы на PHP, в багтрекере скоро будет тикет номер 17000. И, сука, у нас конфиг композера размером примерно с этот, а это малюсенький сервис, который просто архивирует сообщения.
>но я тут проблемы не вижу - они жрать не просят
А я - вижу. Когда-то давным-давно у нас первопроходцы натаскали зависимостей, и теперь, несмотря на то, что всё лежит локально, бутстрап лезет на какие-то CDN; выполняешь тикет и меняешь input type="text" на input type="number" и модалка с формой просто перестает открываться, потому что плагин для jQuery ожидает только type="text", сука.
Чужой модуль - это куча чужих багов и хуй знает как написанного кода. Ты экономишь полчаса-час работы, прикручивая васянский модуль, а затем живешь с черными ящиками в своем проекте.
Ощущение, что ты просто то ли в композере не разбираешься, то ли еще в чем-то.
> бутстрап лезет на какие-то CDN
При чем тут композер, если бутстрап это JS-код и если он и ставится через менеджер пакетов, то через какой-нибудь bower или yarn. И даже в этом случае он не должен лезить ни на какие CDN.
Просто у вас какой-то инвалид вписал ссылку на CDN и ты теперь винишь в этом композер.
Мог бы исправить, кстати.
> выполняешь тикет и меняешь input type="text" на input type="number" и модалка с формой просто перестает открываться, потому что плагин для jQuery ожидает только type="text"
Это ваши проблемы и композер тут не при чем.
> Чужой модуль - это куча чужих багов и хуй знает как написанного кода.
Не надо ставить все подряд, надо изучить доступные библиотеки и выбрать нормальные.
> Ты экономишь полчаса-час работы, прикручивая васянский модуль, а затем живешь с черными ящиками в своем проекте.
Это несерьезное рассуждение. за сколько часов ты напишешь аналог Доктрины? Или Guzzle?
У нас есть ровно 2 варианта: либо использовать сторонние библиотеки, либо не использовать и писать велосипед. Если мы используем, то либо копируем и ставим все руками, либо перекладываем эту задчу на композер.
В том проекте все зависимости
- Доктрина - для ORM
- migrations - для миграций
- slim, php-view - как фреймворк
- cache - для кеширования
- dom-crawler - для парсинга HTML
- guzzle - как HTTP клиент
И так далее. Расскажи, как обойтись без них и сколько часов ты на этом сэкономишь.
Или вот мой простой скрипт проверки целостности ссылок на сайте: https://github.com/codedokode/pasta-link-checker/blob/master/composer.json - давай, расскажи, без чего тут можно обойтись?
Ощущение, что ты просто то ли в композере не разбираешься, то ли еще в чем-то.
> бутстрап лезет на какие-то CDN
При чем тут композер, если бутстрап это JS-код и если он и ставится через менеджер пакетов, то через какой-нибудь bower или yarn. И даже в этом случае он не должен лезить ни на какие CDN.
Просто у вас какой-то инвалид вписал ссылку на CDN и ты теперь винишь в этом композер.
Мог бы исправить, кстати.
> выполняешь тикет и меняешь input type="text" на input type="number" и модалка с формой просто перестает открываться, потому что плагин для jQuery ожидает только type="text"
Это ваши проблемы и композер тут не при чем.
> Чужой модуль - это куча чужих багов и хуй знает как написанного кода.
Не надо ставить все подряд, надо изучить доступные библиотеки и выбрать нормальные.
> Ты экономишь полчаса-час работы, прикручивая васянский модуль, а затем живешь с черными ящиками в своем проекте.
Это несерьезное рассуждение. за сколько часов ты напишешь аналог Доктрины? Или Guzzle?
У нас есть ровно 2 варианта: либо использовать сторонние библиотеки, либо не использовать и писать велосипед. Если мы используем, то либо копируем и ставим все руками, либо перекладываем эту задчу на композер.
В том проекте все зависимости
- Доктрина - для ORM
- migrations - для миграций
- slim, php-view - как фреймворк
- cache - для кеширования
- dom-crawler - для парсинга HTML
- guzzle - как HTTP клиент
И так далее. Расскажи, как обойтись без них и сколько часов ты на этом сэкономишь.
Или вот мой простой скрипт проверки целостности ссылок на сайте: https://github.com/codedokode/pasta-link-checker/blob/master/composer.json - давай, расскажи, без чего тут можно обойтись?
я твою позицию понимаю, система разрастается и копит зависимости, а потом ее и еще 25 других встраивают в другую систему и все растет как снежный ком. тревожненько.
но зато
1) RAD
2) я не вижу альтернатив. ты же не будешь писать свои сервисы контейнеров, логгеров, валидаторов и т.д.? а если и будешь, в них будут такие же баги
>первопроходцы натаскали зависимостей
звучит как косяк в архитектуре и кто-то просто не ожидал, что проект выстрелит. ну ничего, так везде
вообще это забавно, т.к. у меня на прошлой работе все было наоборот. почти все компоненты были написаны сотрудниками компании из-за того, что легаси. потом легаси отрефакторили, а сервисы остались собственными. в них везде была какая-то поебень, мешанина подходов и прочее. только сторонние библиотеки доставляли удовольствие при работе с собой
>У нас есть ровно 2 варианта: либо использовать сторонние библиотеки, либо не использовать и писать велосипед
Писать велосипед - это с нуля написать свой DOM-парсер, например. А написать вспомогательный класс из 50-100 строк вместо подтягивания какой-то либы - это нормально. Это как глупые ребята, не шарящие в CSS, везде суют reset.css, потому что им стандартные стили говна в жопу залили, а умные ребята знают, как верстать без таких глупостей.
>Доктрина - для ORM
Пишу класс DBSaver с методами saveUser, saveNebo, saveAllah, куда передаю объекты User, Nebo, Allah.
>migrations - для миграций
Не знаю, что это.
>slim, php-view - как фреймворк
Для роутинга пишу правила регулярками и классы, куда должно улетать исполнение при совпадении.
>cache - для кеширования
Что может быть проще, чем файловый кэш? Сохраняешь файл, при запросе чекаешь, есть ли файл и не тухлый ли он.
> dom-crawler - для парсинга HTML
Тебе из коробки даются либы на любой вкус - https://secure.php.net/manual/en/refs.xml.php
> guzzle - как HTTP клиент
file_get_contents отличный http-клиент.
Для начала хватит кода на гитхабе. Потому что я в основном смотрю код, а прокликать сайт и проверить что все работает, ты можешь и без меня. Но если будет еще и сайт, то может это пригодится.
>вот мой простой скрипт проверки целостности ссылок на сайте: https://github.com/codedokode/pasta-link-checker/blob/master/composer.json - давай, расскажи, без чего тут можно обойтись?
Ну ты дрочишься. Ты прекрасно понимаешь, что мне нужно прочитать и понять весь твой проект, чтобы делать такие заключения.
Давай просто разберем по частям тобой написанное.
Допустим, class Fetcher.
Начнем с того, что я не понимаю, зачем все методы передают друг другу $url, а не хранят его внутри объекта. Почему нельзя создавать инстанс на каждый $url?
$scheme = parse_url($url, PHP_URL_SCHEME);
if ($scheme == 'file') {
return 0;
}
Опа-ча, работаем с урликами, а внутри $url может быть локальный путь. Как так? Урл - это указатель чего-то в сети.
>getDomainForPause
Хм, что это такое и что оно делает
>parse_url($url, PHP_URL_HOST)
Вау, стоило выносить и давать загадочное имя.
Оп-па, у функции pause сайд-эффект - она сохраняет время последнего запроса. Причем она делает это до запроса. Таким образом, $this->interval соблюдаться не будет. Ведь http-реквест может затормозить в любой момент - на открытии сокета, на открытии сокета сервером, на выдаче первого HTTP-заголовка, на выдаче любой порции стрима, где угодно. Реквест может проходить сколько угодно секунд, и сервер может контролировать частоту твоих запросов от закрытия сокета, например. Но вот беда - сокет может держаться и больше дефолтных трез секунд, и в итоге ты сделаешь два последовательных запроса, а юзер твоего кода мог ожидать 3 секунды задержки.
>if ($response->getStatusCode() != 200)
Код 203 равен коду 200, если информация берется из кэша сервера. Я на одном проекте отдаю 203, если предполагаю, что в базе может быть информация актуальнее, но репликация еще не произошла.
Код 300 может быть отдан, если страница либо файл доступны в разных форматах.
А еще можно получить 101, если сайт хочет работать только по HTTP/2.
Во всех этих случаях юзер получает сайт, ничего не подозревая, а у тебя - ошибка.
>$response->getStatusCode() >= 300 &&
$response->getStatusCode() < 400 &&
$response->hasHeader('Location')
У нас код 300 и Location. Нас хотят перенаправить? Не обязательно. Файл либо страница доступны в разных форматах, и юзер волен выбрать, в каком он хочет получить. При этом Location определяет дефолтный выбор, куда браузер может, но не обязан перейти.
Для юзера это будет абсолютно обычная страница, как код 200.
Вообще, очень странно, что функция fetchUrl заодно выносит какие-то вердикты и просто не возвращает $response. Любые вынесения вердиктов стоит делать методами в классе ResponseMetadata.
if (!$type) {
$errorText = "No Content-Type";
Сервер не обязан отсылать Content-Type. Если его нет, браузер угадывает его по сигнатуре первых байтов.
if (!preg_match("#^text/html#i", $type)) {
$errorText = "Content-Type invalid: $type";
application/xhtml+xml, application/xml и text/plain грустят.
text/vnd.wap.wml и не надеется, что про него вспомнят некоторые олдфаги.
Преимуществ guzzle не увидел. Мало того, если ты спустишься на уровень сокетов, сможешь просто закрывать его после получения заголовков через GET. Будет тот же HEAD, только без возможных 405.
>вот мой простой скрипт проверки целостности ссылок на сайте: https://github.com/codedokode/pasta-link-checker/blob/master/composer.json - давай, расскажи, без чего тут можно обойтись?
Ну ты дрочишься. Ты прекрасно понимаешь, что мне нужно прочитать и понять весь твой проект, чтобы делать такие заключения.
Давай просто разберем по частям тобой написанное.
Допустим, class Fetcher.
Начнем с того, что я не понимаю, зачем все методы передают друг другу $url, а не хранят его внутри объекта. Почему нельзя создавать инстанс на каждый $url?
$scheme = parse_url($url, PHP_URL_SCHEME);
if ($scheme == 'file') {
return 0;
}
Опа-ча, работаем с урликами, а внутри $url может быть локальный путь. Как так? Урл - это указатель чего-то в сети.
>getDomainForPause
Хм, что это такое и что оно делает
>parse_url($url, PHP_URL_HOST)
Вау, стоило выносить и давать загадочное имя.
Оп-па, у функции pause сайд-эффект - она сохраняет время последнего запроса. Причем она делает это до запроса. Таким образом, $this->interval соблюдаться не будет. Ведь http-реквест может затормозить в любой момент - на открытии сокета, на открытии сокета сервером, на выдаче первого HTTP-заголовка, на выдаче любой порции стрима, где угодно. Реквест может проходить сколько угодно секунд, и сервер может контролировать частоту твоих запросов от закрытия сокета, например. Но вот беда - сокет может держаться и больше дефолтных трез секунд, и в итоге ты сделаешь два последовательных запроса, а юзер твоего кода мог ожидать 3 секунды задержки.
>if ($response->getStatusCode() != 200)
Код 203 равен коду 200, если информация берется из кэша сервера. Я на одном проекте отдаю 203, если предполагаю, что в базе может быть информация актуальнее, но репликация еще не произошла.
Код 300 может быть отдан, если страница либо файл доступны в разных форматах.
А еще можно получить 101, если сайт хочет работать только по HTTP/2.
Во всех этих случаях юзер получает сайт, ничего не подозревая, а у тебя - ошибка.
>$response->getStatusCode() >= 300 &&
$response->getStatusCode() < 400 &&
$response->hasHeader('Location')
У нас код 300 и Location. Нас хотят перенаправить? Не обязательно. Файл либо страница доступны в разных форматах, и юзер волен выбрать, в каком он хочет получить. При этом Location определяет дефолтный выбор, куда браузер может, но не обязан перейти.
Для юзера это будет абсолютно обычная страница, как код 200.
Вообще, очень странно, что функция fetchUrl заодно выносит какие-то вердикты и просто не возвращает $response. Любые вынесения вердиктов стоит делать методами в классе ResponseMetadata.
if (!$type) {
$errorText = "No Content-Type";
Сервер не обязан отсылать Content-Type. Если его нет, браузер угадывает его по сигнатуре первых байтов.
if (!preg_match("#^text/html#i", $type)) {
$errorText = "Content-Type invalid: $type";
application/xhtml+xml, application/xml и text/plain грустят.
text/vnd.wap.wml и не надеется, что про него вспомнят некоторые олдфаги.
Преимуществ guzzle не увидел. Мало того, если ты спустишься на уровень сокетов, сможешь просто закрывать его после получения заголовков через GET. Будет тот же HEAD, только без возможных 405.
Ну и про черные ящики. Вот ты предполагаешь, что Grunt вернет тебе Content-Type так, что строка будет начинаться с text/...
А что будет, если сервер поставит два пробела между двоеточием и значением? Это валидный заголовок. У тебя будет первый пробел? Или не будет? Ты не можешь ответить на этот вопрос. Это не твой код.
1280x720, 0:44
>основная функция spellNumber(), которая принимает на вход большое число, разбивает его на части по 3 цифры и вызывая указанные выше функции, получает число прописью.
И как мне это сделать, если
>Некоторые делают ошибку, пытаясь работать с числами строковыми функциями вроде mb_substr() или mb_strlen(). Это неправильно.
Тогда как мне
>разбивает его на части по 3 цифры
Нужно число делить на 10, сотни и тысячи для того, чтобы разделить?
Так, я придумал.
Сперва поделить число на десятки миллионов, если делится, то задать переменной то количество десятков и форму слова миллион\ов\а.
Потом взять остаток и его уже делить на миллионы. Повторить то же, что и с десятками.
Проделывать так до единиц.
Потом вывести эти переменные.
Ну проект довольно маленький, и он на ООП, так что не требуется его целиком изучать, можно смотреть отдельный класс. И да, он не идеальный, так как написан по сути (видно по коммитам) в 2 присеста и мне надо было получить что-то работабщее побыстрее. И я получил - теперь я могу получить список "сомнительных", потенциально сломанных или изменившихся ссылок для ручной перепроверки, не обходя все свои уроки вручную. Разве это не прекрасно?
Также, я думал использовать эту проверялку через Travis (CI сервис), чтобы при каждом коммите Travis бы скачивал мой репозиторий с уроками или сайтом, скачивал проверяльщик, проверял все ссылки, и я бы мог видеть по значку в ридми, что появились сломанные ссылки. И да, у меня еще есть (пока очень сырой и требующий работы) набор скриптов для проверки правописания через hunspell.
> Начнем с того, что я не понимаю, зачем все методы передают друг другу $url, а не хранят его внутри объекта. Почему нельзя создавать инстанс на каждый $url?
Потому, что Fetcher - это сервис, который может сделать много запросов. Не вижу, в чем мне выгода на каждый запрос создавать новый Fetcher. Более того, у него есть состояние - он запоминает время последней отправки запроса к каждому домену, чтобы не делать запросы к одному домену чаще, чем раз в 3 секунды.
И кстати, я там в checker.php прикрутил костылек, чтобы делать сначала запросы к доменам, которые с меньшей вероятностью заблокируются. Хотя, конечно, самое правильное решение было бы сделать параллельный запрашиватель файлов, но это бы потребовало намного больше времени на написание и отладку (хотя в Guzzle вроде что-то такое есть, может когда-нибудь гляну).
И заметь, я еще стараюсь по возможности делать HEAD, если он поддерживается сервером и если мне не нужно тело запроса. И умею перепрыгивать на GET, если сервер отказывается выполнять этот метод.
Вот реальная проблема, которую я пока не исправил - это отстутствие четкого разделения обязанностей между Fetcher и LinkChecker, это да.
> Опа-ча, работаем с урликами, а внутри $url может быть локальный путь. Как так? Урл - это указатель чего-то в сети.
Вообще, нет https://ru.wikipedia.org/wiki/URL#Схемы_(протоколы)_URL
> file — Имя локального файла
> tel — звонок по указанному телефону (хотя, тут может правильнее было бы использовать URN)
> data — Непосредственные данные (Data: URL)
Поддержка file пока не готова, но планируется на будущее, чтобы можно было проверять ссылки в папке с HTML файлами. Удобно же.
>>getDomainForPause
> Хм, что это такое и что оно делает
Наверно неудачно названо и не хватает комментария. Определяет ключ, по которому проверяется частота запросов. Может быть, я захочу завтра ограничивать частоту запросов не по всему домену, а по домену 2-го уровня.
> Оп-па, у функции pause сайд-эффект - она сохраняет время последнего запроса.
В этом ее предназначение - сделать паузу необходимой длины перед отправкой запроса.
> Но вот беда - сокет может держаться и больше дефолтных трез секунд, и в итоге ты сделаешь два последовательных запроса, а юзер твоего кода мог ожидать 3 секунды задержки.
interval это интервал, чаще которого нельзя посылать запросы к одному домену.
> Код 203 равен коду 200, если информация берется из кэша сервера
Не исключаю, что мой код не идеален. Однако, я не сталкивался пока с кодом 203, и никто мне не писал про этов Issues - значит, пока можно не тратить время на решение этой проблемы. Однако, записал твою идею в TODO.
Я тебе могу рассказать про более интересную проблему - обнаружение припаркованных (то есть потерянных или проданных владельцем) доменов. Эти домены отдают 200 на любой URL, но естественно, не содержат никакой полезной информации, а лишь список рекламных ссылок. Пример ww1.verginmobile.com
Другая проблема - некоторые домены не любят ботов (а я честно подписываю User-Agent) и отдают им ответ 403 или редиректят на localhost (я не шучу). Видимо, придется как-то вручную сделать исключения по доменам. Не знаю, как это лучше оформить, чтобы не хардкодить.
Третья проблема - проверка ссылок вроде mega.nz/#12345 (хеш там проверяется JS-кодом, даже если файлы недоступны, отдается 200) или rghost.net/12345 (если файл удален, он все равно отдает страницу 200). Опять же, наверно, нужны исключения на основе домена.
Сейчас эти проблемы актуальнее, чем экзотичные коды ответа.
> А еще можно получить 101, если сайт хочет работать только по HTTP/2.
Надеюсь, что Гузл это сам обработает, так как код 1xx - это информационный код, который не завершает HTTP запрос, как я помню, и за ним придет настоящий код. Если нет, то просматривая список ошибок, я увижу проблему и исправлю код.
> У нас код 300 и Location. Нас хотят перенаправить? Не обязательно.
Странно, мне кажется, что обязательно. Но я, конечно, так тщательно спеку HTTP не читал. Можешь дать пример страницы, где есть 3xx но это не редирект?
Ну и как я понимаю, большинство браузеров отредиректит пользователя, значит, ссылка у меня в статье неправильная. Может, конечно, надо различать виды редиректов, 301 от других, но по факту на сайте может быть криво настроен код, и мой скрипт должен работать в этом неидеальном мире.
> Вообще, очень странно, что функция fetchUrl заодно выносит какие-то вердикты и просто не возвращает $response. Любые вынесения вердиктов стоит делать методами в классе ResponseMetadata.
Я думал, но тогда нам придется просто засунуть туда целиком содержимое Response, а он еще и не сериализируемый и в кеш не пойдет. Я подумал, что проще будет переименовать его в CheckResult.
> Сервер не обязан отсылать Content-Type. Если его нет, браузер угадывает его по сигнатуре первых байтов.
Не уверен. Знаю, что так любил делать ИЕ (content sniffing) и это приводило к уязвимостям. У тебя есть ссылка по теме?
> application/xhtml+xml, application/xml и text/plain грустят.
ты бы мог еще добавить, что в статье может стоять ссылка на картинку или PDF. да, это написано в TODO. Тут еще сложность, что мне надо как-то отличать технические страницы с ошибкой от нормальных.
> Преимуществ guzzle не увидел.
Мне не пришлось писать свой HTTP клиент, объекты для представления HTTP запросов и ответов. Не пришлось изучать кучу тонкостей, про которые ты написал (про 203 я например не знал), это уже скорее всего сделано за меня. Если это сделано - прекрасно, я сэкономил время. Если нет - то в любом случае, и со сторонней библиотекой, и со своей, придется тратить время на решение.
Чтобы делать запросы, нам в любом случае нужен HTTP клиент. Кто-то должен его написать, отладить, протестировать (а тесты тоже требуют немало времени), задокументировать, поддерживать, исправлять баги. При использовании сторонней библиотеки делать это придется не мне, я экономлю время.
Или по твоему, каждый разработчик в мире должен писать свою версию HTTP клиента? Или может, лучше просто взять библиотеку и исправить, если в ней чего-то не хватает? Так все сообщество будет в выгоде, получив твои исправления.
Ты не забывай, что приоритеты могут быть разными. Часто программисты пытаются оптимизировать код по каким-то техническим критериям: время работы, потребление памяти, уровень соответствия спецификации, покрытие тестами, субъективное восприятие качества кода. Но если это не учебный код, часто надо учитывать еще и бизнес-факторы (время/деньги). Ну например, бизнес может предпочесть получить код, потребляющий 1 Гб памяти и написанный за час коду, который потребляет 100 Мб, но требует 20 часов на написание. И даже если проект некоммерческий, бизнес-критерии к нему применимы, так как ты тратишь на него свое время и время доровоьцев, которое ограничено. То есть опен сурс живет по тем же экономическим законам.
Для меня это всего лишь вспомогательный инструмент, задача у меня уменьшить количество битых ссылок. В идеале до нуля, но не обязательно.
Ну проект довольно маленький, и он на ООП, так что не требуется его целиком изучать, можно смотреть отдельный класс. И да, он не идеальный, так как написан по сути (видно по коммитам) в 2 присеста и мне надо было получить что-то работабщее побыстрее. И я получил - теперь я могу получить список "сомнительных", потенциально сломанных или изменившихся ссылок для ручной перепроверки, не обходя все свои уроки вручную. Разве это не прекрасно?
Также, я думал использовать эту проверялку через Travis (CI сервис), чтобы при каждом коммите Travis бы скачивал мой репозиторий с уроками или сайтом, скачивал проверяльщик, проверял все ссылки, и я бы мог видеть по значку в ридми, что появились сломанные ссылки. И да, у меня еще есть (пока очень сырой и требующий работы) набор скриптов для проверки правописания через hunspell.
> Начнем с того, что я не понимаю, зачем все методы передают друг другу $url, а не хранят его внутри объекта. Почему нельзя создавать инстанс на каждый $url?
Потому, что Fetcher - это сервис, который может сделать много запросов. Не вижу, в чем мне выгода на каждый запрос создавать новый Fetcher. Более того, у него есть состояние - он запоминает время последней отправки запроса к каждому домену, чтобы не делать запросы к одному домену чаще, чем раз в 3 секунды.
И кстати, я там в checker.php прикрутил костылек, чтобы делать сначала запросы к доменам, которые с меньшей вероятностью заблокируются. Хотя, конечно, самое правильное решение было бы сделать параллельный запрашиватель файлов, но это бы потребовало намного больше времени на написание и отладку (хотя в Guzzle вроде что-то такое есть, может когда-нибудь гляну).
И заметь, я еще стараюсь по возможности делать HEAD, если он поддерживается сервером и если мне не нужно тело запроса. И умею перепрыгивать на GET, если сервер отказывается выполнять этот метод.
Вот реальная проблема, которую я пока не исправил - это отстутствие четкого разделения обязанностей между Fetcher и LinkChecker, это да.
> Опа-ча, работаем с урликами, а внутри $url может быть локальный путь. Как так? Урл - это указатель чего-то в сети.
Вообще, нет https://ru.wikipedia.org/wiki/URL#Схемы_(протоколы)_URL
> file — Имя локального файла
> tel — звонок по указанному телефону (хотя, тут может правильнее было бы использовать URN)
> data — Непосредственные данные (Data: URL)
Поддержка file пока не готова, но планируется на будущее, чтобы можно было проверять ссылки в папке с HTML файлами. Удобно же.
>>getDomainForPause
> Хм, что это такое и что оно делает
Наверно неудачно названо и не хватает комментария. Определяет ключ, по которому проверяется частота запросов. Может быть, я захочу завтра ограничивать частоту запросов не по всему домену, а по домену 2-го уровня.
> Оп-па, у функции pause сайд-эффект - она сохраняет время последнего запроса.
В этом ее предназначение - сделать паузу необходимой длины перед отправкой запроса.
> Но вот беда - сокет может держаться и больше дефолтных трез секунд, и в итоге ты сделаешь два последовательных запроса, а юзер твоего кода мог ожидать 3 секунды задержки.
interval это интервал, чаще которого нельзя посылать запросы к одному домену.
> Код 203 равен коду 200, если информация берется из кэша сервера
Не исключаю, что мой код не идеален. Однако, я не сталкивался пока с кодом 203, и никто мне не писал про этов Issues - значит, пока можно не тратить время на решение этой проблемы. Однако, записал твою идею в TODO.
Я тебе могу рассказать про более интересную проблему - обнаружение припаркованных (то есть потерянных или проданных владельцем) доменов. Эти домены отдают 200 на любой URL, но естественно, не содержат никакой полезной информации, а лишь список рекламных ссылок. Пример ww1.verginmobile.com
Другая проблема - некоторые домены не любят ботов (а я честно подписываю User-Agent) и отдают им ответ 403 или редиректят на localhost (я не шучу). Видимо, придется как-то вручную сделать исключения по доменам. Не знаю, как это лучше оформить, чтобы не хардкодить.
Третья проблема - проверка ссылок вроде mega.nz/#12345 (хеш там проверяется JS-кодом, даже если файлы недоступны, отдается 200) или rghost.net/12345 (если файл удален, он все равно отдает страницу 200). Опять же, наверно, нужны исключения на основе домена.
Сейчас эти проблемы актуальнее, чем экзотичные коды ответа.
> А еще можно получить 101, если сайт хочет работать только по HTTP/2.
Надеюсь, что Гузл это сам обработает, так как код 1xx - это информационный код, который не завершает HTTP запрос, как я помню, и за ним придет настоящий код. Если нет, то просматривая список ошибок, я увижу проблему и исправлю код.
> У нас код 300 и Location. Нас хотят перенаправить? Не обязательно.
Странно, мне кажется, что обязательно. Но я, конечно, так тщательно спеку HTTP не читал. Можешь дать пример страницы, где есть 3xx но это не редирект?
Ну и как я понимаю, большинство браузеров отредиректит пользователя, значит, ссылка у меня в статье неправильная. Может, конечно, надо различать виды редиректов, 301 от других, но по факту на сайте может быть криво настроен код, и мой скрипт должен работать в этом неидеальном мире.
> Вообще, очень странно, что функция fetchUrl заодно выносит какие-то вердикты и просто не возвращает $response. Любые вынесения вердиктов стоит делать методами в классе ResponseMetadata.
Я думал, но тогда нам придется просто засунуть туда целиком содержимое Response, а он еще и не сериализируемый и в кеш не пойдет. Я подумал, что проще будет переименовать его в CheckResult.
> Сервер не обязан отсылать Content-Type. Если его нет, браузер угадывает его по сигнатуре первых байтов.
Не уверен. Знаю, что так любил делать ИЕ (content sniffing) и это приводило к уязвимостям. У тебя есть ссылка по теме?
> application/xhtml+xml, application/xml и text/plain грустят.
ты бы мог еще добавить, что в статье может стоять ссылка на картинку или PDF. да, это написано в TODO. Тут еще сложность, что мне надо как-то отличать технические страницы с ошибкой от нормальных.
> Преимуществ guzzle не увидел.
Мне не пришлось писать свой HTTP клиент, объекты для представления HTTP запросов и ответов. Не пришлось изучать кучу тонкостей, про которые ты написал (про 203 я например не знал), это уже скорее всего сделано за меня. Если это сделано - прекрасно, я сэкономил время. Если нет - то в любом случае, и со сторонней библиотекой, и со своей, придется тратить время на решение.
Чтобы делать запросы, нам в любом случае нужен HTTP клиент. Кто-то должен его написать, отладить, протестировать (а тесты тоже требуют немало времени), задокументировать, поддерживать, исправлять баги. При использовании сторонней библиотеки делать это придется не мне, я экономлю время.
Или по твоему, каждый разработчик в мире должен писать свою версию HTTP клиента? Или может, лучше просто взять библиотеку и исправить, если в ней чего-то не хватает? Так все сообщество будет в выгоде, получив твои исправления.
Ты не забывай, что приоритеты могут быть разными. Часто программисты пытаются оптимизировать код по каким-то техническим критериям: время работы, потребление памяти, уровень соответствия спецификации, покрытие тестами, субъективное восприятие качества кода. Но если это не учебный код, часто надо учитывать еще и бизнес-факторы (время/деньги). Ну например, бизнес может предпочесть получить код, потребляющий 1 Гб памяти и написанный за час коду, который потребляет 100 Мб, но требует 20 часов на написание. И даже если проект некоммерческий, бизнес-критерии к нему применимы, так как ты тратишь на него свое время и время доровоьцев, которое ограничено. То есть опен сурс живет по тем же экономическим законам.
Для меня это всего лишь вспомогательный инструмент, задача у меня уменьшить количество битых ссылок. В идеале до нуля, но не обязательно.
Для меня это всего лишь вспомогательный инструмент, задача у меня уменьшить количество битых ссылок. В идеале до нуля, но не обязательно.
> Мало того, если ты спустишься на уровень сокетов, сможешь просто закрывать его после получения заголовков через GET. Будет тот же HEAD, только без возможных 405.
Это костыльно и недружелюбно по отношению к серверу, зачем его заставлять генерировать ответ, который мне не нужен? Ну и я подозреваю, что в Guzzle это тоже возможно (ограничивать размер ответа 0 байтами).
- тут для Guzzle 6 https://stackoverflow.com/questions/26507081/limit-the-request-size-when-using-guzzle-goutte
- также можно костылем передать нужные опции для curl
Я кстати, когда-то давно тоже страдал изобретением велосипедов, но, к счастью, много времени на это потратить не успел.
Но вообще, спасибо за подробный пост, я даже узнал что-то новое для себя. Не так часто такое бывает. Заходи почаще в наш тред, у нас есть и сложные задачки (как тебе задача на SPA из Оп поста?), может тебе интересно будет что-то поделать.
>>32342
Я с таким не сталкивался. Если такое произойдет, то я увижу ошибку, начну разбирать ее и либо 1) найду баг в своем коде и исправлю 2) пойму что проблема на сервере и сделаю костыль дял нее 3) пойму что проблема в сторонней библиотеке, зарепорчу баг, и пока у себя сделаю костыль для исправления.
Я ведь точно так же и в своем коде не предусмотрю все возможные ситуации. да и я не хочу писать свой клиент, параллельно разгребая 100-страничный RFC.
>>32364
Работать через строки неудобно. PHP может иногда преобразовать большие числа к виду "1.23456e10" (подробнее: https://ru.wikipedia.org/wiki/Экспоненциальная_запись#Компьютерный_способ_экспоненциальной_записи ) и строчные функции тут тебя подведут.
Используй математику. Есть 2 функции для разделения чисел на части, $x % 1000 - берет 3 последние цифры, floor($x / 1000) - отбрасывает 3 последние цифры.
Для меня это всего лишь вспомогательный инструмент, задача у меня уменьшить количество битых ссылок. В идеале до нуля, но не обязательно.
> Мало того, если ты спустишься на уровень сокетов, сможешь просто закрывать его после получения заголовков через GET. Будет тот же HEAD, только без возможных 405.
Это костыльно и недружелюбно по отношению к серверу, зачем его заставлять генерировать ответ, который мне не нужен? Ну и я подозреваю, что в Guzzle это тоже возможно (ограничивать размер ответа 0 байтами).
- тут для Guzzle 6 https://stackoverflow.com/questions/26507081/limit-the-request-size-when-using-guzzle-goutte
- также можно костылем передать нужные опции для curl
Я кстати, когда-то давно тоже страдал изобретением велосипедов, но, к счастью, много времени на это потратить не успел.
Но вообще, спасибо за подробный пост, я даже узнал что-то новое для себя. Не так часто такое бывает. Заходи почаще в наш тред, у нас есть и сложные задачки (как тебе задача на SPA из Оп поста?), может тебе интересно будет что-то поделать.
>>32342
Я с таким не сталкивался. Если такое произойдет, то я увижу ошибку, начну разбирать ее и либо 1) найду баг в своем коде и исправлю 2) пойму что проблема на сервере и сделаю костыль дял нее 3) пойму что проблема в сторонней библиотеке, зарепорчу баг, и пока у себя сделаю костыль для исправления.
Я ведь точно так же и в своем коде не предусмотрю все возможные ситуации. да и я не хочу писать свой клиент, параллельно разгребая 100-страничный RFC.
>>32364
Работать через строки неудобно. PHP может иногда преобразовать большие числа к виду "1.23456e10" (подробнее: https://ru.wikipedia.org/wiki/Экспоненциальная_запись#Компьютерный_способ_экспоненциальной_записи ) и строчные функции тут тебя подведут.
Используй математику. Есть 2 функции для разделения чисел на части, $x % 1000 - берет 3 последние цифры, floor($x / 1000) - отбрасывает 3 последние цифры.
Ты бы изучил рассматриваемые библиотеки получше. Может и тебе пригодятся ;)
> Это как глупые ребята, не шарящие в CSS, везде суют reset.css
Это плохой подход, сбросить все стили, а потом переопределять их заново или получить текст без абзацев.
> Пишу класс DBSaver с методами saveUser, saveNebo, saveAllah, к
В Доктрине намного больше. Там еще есть загрузка объектов из БД, ленивая загрузка, поддержка отношений (ну-ка, напиши-ка), автоматический поиск изменений в объектах и тд. Это все экономит время.
>>migrations - для миграций
> Не знаю, что это.
Миграции позволяют фиксировать в репозитории изменения в структуре БД, привязывать их к коммитам, воссоздавать структуру БД в любой точке истории, позволяют обновлять структуру БД без потери данных в ней, передавать эту информацию другим разработчикам. Иногда позволяют выражать изменения структуры БД не на SQL, чем достигается поддержка нескольких СУБД. А как ты в своих проектах обновляешь структуру БД? Вот понадобилось тебе например таблицу добавить, или поле, или индекс?
Я обычно пишу миграции руками на SQL, но некоторые любят сначала поменять схему БД вручную и потом сгенерировать миграицию из разницы схем новой и старой версии.
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/toc.html
> Для роутинга пишу правила регулярками и классы, куда должно улетать исполнение при совпадении.
Изобретаешь велосипед. Symfony Routing например умеет генерировать из удобного читабельного YAML конфига (который читать проще чем твой код) код с регулярками ради оптимизации: https://symfony.com/doc/current/routing.html
Попробуй, только советую не использовать аннотации, а использовать YAML.
> Что может быть проще, чем файловый кэш? Сохраняешь файл, при запросе чекаешь, есть ли файл и не тухлый ли он.
Так я это и делаю, только не пишу этот код сам. И получаю кучу готовых видов кешей, могу кеширвоать данные вообще куда угодно, хоть в шареную память.
> Тебе из коробки даются либы на любой вкус - https://secure.php.net/manual/en/refs.xml.php
Они очень неудобные и не поддерживают CSS синтаксис (а в XSLT искать классы неудобно и громоздко).
> file_get_contents отличный http-клиент.
Нет, чтобы получить просто заголовки, тебе придется писать код, чтобы добавить таймаут, еще какой-то код и так далее.
И кстати, я использую из Гуззла еще URL resolver - он умеет делать так: http://example.com/a/b + ../file.txt = http://example.com/file.txt . На сайтах ведь встречаются относительные ссылки. Ты его тоже предлагаешь самому писать?
В любом случае, кто-то должен написать, протестировать, поддерживать библиоетку - либо ты, либо сообщество. Не вижу в чем выгода тратить время на переизобретение того, что уже написано. И что я теряю, используя готовую библиотеку.
Тот проект (phpclub.tech) пишу не я, а аноны сами организовались и пишут. У них есть много своих дел, работа, учеба, и тд. Вряд ли они могут себе позволить тратить время на переизобретение ORM или HTTP клиента.
Ты бы изучил рассматриваемые библиотеки получше. Может и тебе пригодятся ;)
> Это как глупые ребята, не шарящие в CSS, везде суют reset.css
Это плохой подход, сбросить все стили, а потом переопределять их заново или получить текст без абзацев.
> Пишу класс DBSaver с методами saveUser, saveNebo, saveAllah, к
В Доктрине намного больше. Там еще есть загрузка объектов из БД, ленивая загрузка, поддержка отношений (ну-ка, напиши-ка), автоматический поиск изменений в объектах и тд. Это все экономит время.
>>migrations - для миграций
> Не знаю, что это.
Миграции позволяют фиксировать в репозитории изменения в структуре БД, привязывать их к коммитам, воссоздавать структуру БД в любой точке истории, позволяют обновлять структуру БД без потери данных в ней, передавать эту информацию другим разработчикам. Иногда позволяют выражать изменения структуры БД не на SQL, чем достигается поддержка нескольких СУБД. А как ты в своих проектах обновляешь структуру БД? Вот понадобилось тебе например таблицу добавить, или поле, или индекс?
Я обычно пишу миграции руками на SQL, но некоторые любят сначала поменять схему БД вручную и потом сгенерировать миграицию из разницы схем новой и старой версии.
http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/toc.html
> Для роутинга пишу правила регулярками и классы, куда должно улетать исполнение при совпадении.
Изобретаешь велосипед. Symfony Routing например умеет генерировать из удобного читабельного YAML конфига (который читать проще чем твой код) код с регулярками ради оптимизации: https://symfony.com/doc/current/routing.html
Попробуй, только советую не использовать аннотации, а использовать YAML.
> Что может быть проще, чем файловый кэш? Сохраняешь файл, при запросе чекаешь, есть ли файл и не тухлый ли он.
Так я это и делаю, только не пишу этот код сам. И получаю кучу готовых видов кешей, могу кеширвоать данные вообще куда угодно, хоть в шареную память.
> Тебе из коробки даются либы на любой вкус - https://secure.php.net/manual/en/refs.xml.php
Они очень неудобные и не поддерживают CSS синтаксис (а в XSLT искать классы неудобно и громоздко).
> file_get_contents отличный http-клиент.
Нет, чтобы получить просто заголовки, тебе придется писать код, чтобы добавить таймаут, еще какой-то код и так далее.
И кстати, я использую из Гуззла еще URL resolver - он умеет делать так: http://example.com/a/b + ../file.txt = http://example.com/file.txt . На сайтах ведь встречаются относительные ссылки. Ты его тоже предлагаешь самому писать?
В любом случае, кто-то должен написать, протестировать, поддерживать библиоетку - либо ты, либо сообщество. Не вижу в чем выгода тратить время на переизобретение того, что уже написано. И что я теряю, используя готовую библиотеку.
Тот проект (phpclub.tech) пишу не я, а аноны сами организовались и пишут. У них есть много своих дел, работа, учеба, и тд. Вряд ли они могут себе позволить тратить время на переизобретение ORM или HTTP клиента.
К хорошему быстро привыкаешь. Я когда начну писать простой скрипт (тот же проект для проверки битых ссылок), обнаруживаю, что мне нужны сторонние библиотеки. С ними все проще. Ну вот даже если открыть https://github.com/codedokode/pasta-link-checker/blob/master/checker.php:
- CacertBundle дает мне файл cacert.pem для проверки HTTPS-сертификатов. А как же иначе, без корневого набора сертификатов ты HTTPS корректно выполнять не сможешь, и в той же винде например у PHP этих корневых сертификатов нет, использовать системные он видимо не умеет. В линуксе дела получше, но тоже наверно зависит от репозитория, так что проще исопльзовать готовое решение.
- ConsoleOutput и ConsoleLogger из symfony/console дают мне готовый PSR-логгер. Я могу легко перенаправить сообщения куда хочу и переключать подробный/краткий вывод логов.
- new InputDefinition из компонента symfony/console дает мне средство для разбора аргументов из $argv, а также умеет генерировать help по ним. Я знаю про getopt, он ужасен и сквозит своей сишной сущностью.
- guzzle делает HTTP запросы, и вроде как даже умеет параллельность, если не умеет, я могу взять клиент из ReactPHP
- FilesystemCache отвечает за кеширование с проверкой времени, и умеет очищать кеш. Это не очень долго писать, но ведь потом захочется сделать тесты, добавить какие-то фичи, и тд, и куча времени уйдет.
- symfony/dom-crawler и symfony/css-selector не идеальны, но парсить ими HTML удобнее, чем встроенным в PHP XML-расширением. Чего там стоит возня с настройкой кодировки или перехват ошибок.
Каждая зависимость в моем проекте обоснована и добавлена на основе взвешивания ее преимуществ/недостатков.
Ты наверно и шаблонизаторы не используешь? Зря, советую тебе изучить библиотеки, которые использовал я и аноны из phpclub, и они тебе не раз пригодятся. Я всегда готов что-то по ним подсказать и поделиться опытом.
Вот ты там выше анону написал про кучу тонкостей работы с HTTP, но ведь многое из этого, если не все, уже решено в Гуззле.
>>31930
Что сложного в пагинации тредов? Берешь таблицу тредов и делаешь SELECT ... FROM threads ORDER BY bump_date DESC LIMIT :x OFFSET :y. Если тредов не тысячи, это будет быстро работать.
>>31896
Тут стоит просто поставить себе образец Symfony приложения (например https://github.com/symfony/demo/ ) и смотреть код, начиная с public/index.php.
Там происходит все примерно так:
- инициализируем автозагрузку
- создаем объект класса Kernel (я думаю, это будет App\Kernel: https://github.com/symfony/demo/blob/master/src/Kernel.php ). Его задача - инициализация фреймворка, загрузка DI контейнера, бандлов, разбор конфигов.
- инициализируем DI контейнер
- загружаем все бандлы (они тоже объекты), инициализиурем их, они читают свои конфиги и настриваются, ставят обработчики разных событий. Этот этап зверски оптимизирован и использует кеш, чтобы не делать это на каждом запросе, но пока на кеш можно не смотреть. В Симфони есть несколько встроенных бандлов (увидеть их список можно в AppKernel), и тебе придется посмотреть их код тоже.
- создаем Request, передаем его Kernel для обработки
- создаем по моему HttpKernel и заходим в цикл обработки запроса: https://symfony.com/doc/current/components/http_kernel.html
- на всех этапах работы HttpKernel в процесс вмешиваются бандлы, и что-то делают свое. Роутер например разбирает URL запроса и ищет соответствие ему в конфиге роутинга, фаерволл проверяет права доступа
- затем Httpkernel определяет текущий контроллер и запускает его
- контроллер получает на вход Request и должен вернуть Response (HTTP-ответ с телом страницы внутри)
- HttpKernel отдает Response юзеру
Также, прочитай про структуру приложения, что такое бандлы (расширения к ядру фреймворка, которые могут добавлять свои сервисы, роуты, обработчики событий и тд).
Также, есть подвохи: например, ты там не найдешь прямого вызова роутера для разбора URL или вызова фаерволла, который проверяет права доступа. Бандл с роутером просто в своем конфиге прописывает вызор роутера перед обработкой запроса HttpKernel, роутер разбирает URL и добавляет результаты разбора назад в объект запроса. Это специально так сделано, чтобы банглы могли менять процесс обработки запроса и отдачи ответа.
К хорошему быстро привыкаешь. Я когда начну писать простой скрипт (тот же проект для проверки битых ссылок), обнаруживаю, что мне нужны сторонние библиотеки. С ними все проще. Ну вот даже если открыть https://github.com/codedokode/pasta-link-checker/blob/master/checker.php:
- CacertBundle дает мне файл cacert.pem для проверки HTTPS-сертификатов. А как же иначе, без корневого набора сертификатов ты HTTPS корректно выполнять не сможешь, и в той же винде например у PHP этих корневых сертификатов нет, использовать системные он видимо не умеет. В линуксе дела получше, но тоже наверно зависит от репозитория, так что проще исопльзовать готовое решение.
- ConsoleOutput и ConsoleLogger из symfony/console дают мне готовый PSR-логгер. Я могу легко перенаправить сообщения куда хочу и переключать подробный/краткий вывод логов.
- new InputDefinition из компонента symfony/console дает мне средство для разбора аргументов из $argv, а также умеет генерировать help по ним. Я знаю про getopt, он ужасен и сквозит своей сишной сущностью.
- guzzle делает HTTP запросы, и вроде как даже умеет параллельность, если не умеет, я могу взять клиент из ReactPHP
- FilesystemCache отвечает за кеширование с проверкой времени, и умеет очищать кеш. Это не очень долго писать, но ведь потом захочется сделать тесты, добавить какие-то фичи, и тд, и куча времени уйдет.
- symfony/dom-crawler и symfony/css-selector не идеальны, но парсить ими HTML удобнее, чем встроенным в PHP XML-расширением. Чего там стоит возня с настройкой кодировки или перехват ошибок.
Каждая зависимость в моем проекте обоснована и добавлена на основе взвешивания ее преимуществ/недостатков.
Ты наверно и шаблонизаторы не используешь? Зря, советую тебе изучить библиотеки, которые использовал я и аноны из phpclub, и они тебе не раз пригодятся. Я всегда готов что-то по ним подсказать и поделиться опытом.
Вот ты там выше анону написал про кучу тонкостей работы с HTTP, но ведь многое из этого, если не все, уже решено в Гуззле.
>>31930
Что сложного в пагинации тредов? Берешь таблицу тредов и делаешь SELECT ... FROM threads ORDER BY bump_date DESC LIMIT :x OFFSET :y. Если тредов не тысячи, это будет быстро работать.
>>31896
Тут стоит просто поставить себе образец Symfony приложения (например https://github.com/symfony/demo/ ) и смотреть код, начиная с public/index.php.
Там происходит все примерно так:
- инициализируем автозагрузку
- создаем объект класса Kernel (я думаю, это будет App\Kernel: https://github.com/symfony/demo/blob/master/src/Kernel.php ). Его задача - инициализация фреймворка, загрузка DI контейнера, бандлов, разбор конфигов.
- инициализируем DI контейнер
- загружаем все бандлы (они тоже объекты), инициализиурем их, они читают свои конфиги и настриваются, ставят обработчики разных событий. Этот этап зверски оптимизирован и использует кеш, чтобы не делать это на каждом запросе, но пока на кеш можно не смотреть. В Симфони есть несколько встроенных бандлов (увидеть их список можно в AppKernel), и тебе придется посмотреть их код тоже.
- создаем Request, передаем его Kernel для обработки
- создаем по моему HttpKernel и заходим в цикл обработки запроса: https://symfony.com/doc/current/components/http_kernel.html
- на всех этапах работы HttpKernel в процесс вмешиваются бандлы, и что-то делают свое. Роутер например разбирает URL запроса и ищет соответствие ему в конфиге роутинга, фаерволл проверяет права доступа
- затем Httpkernel определяет текущий контроллер и запускает его
- контроллер получает на вход Request и должен вернуть Response (HTTP-ответ с телом страницы внутри)
- HttpKernel отдает Response юзеру
Также, прочитай про структуру приложения, что такое бандлы (расширения к ядру фреймворка, которые могут добавлять свои сервисы, роуты, обработчики событий и тд).
Также, есть подвохи: например, ты там не найдешь прямого вызова роутера для разбора URL или вызова фаерволла, который проверяет права доступа. Бандл с роутером просто в своем конфиге прописывает вызор роутера перед обработкой запроса HttpKernel, роутер разбирает URL и добавляет результаты разбора назад в объект запроса. Это специально так сделано, чтобы банглы могли менять процесс обработки запроса и отдачи ответа.
Должен направлять, посмотри отладчиком в браузере (Ctrl + Shift + I) на вкладке Network, какие заголовки отдает сервер.
>>30056
>>31288
> ЗАДАЧА: сделать отправку данных на сервер через fsockopen, то есть используя только стандартные возможности php
Почему нельзя использовать Guzzle?
> # С помощью @ подавляю ошибки fsockopen и возвращаю пустую $data
Это плохо, так как мы не узнаем причину ошибки. А чтобы нормально работать с ошибками, лучше всего использовать исключения: https://github.com/codedokode/pasta/blob/master/php/exceptions.md
> # Какая разница между timeout в fsockopen и этой настройкой? Как правильно сделать?
Надо читать мануал, думаю, в timeout ставится таймаут на установку TCP-соединения с сервером, а тут таймаут на ожидание пакета данных.
> fwrite($fp, $head);
Тут ошибка. Ты почему-то думаешь, что все данные отправятся за один запрос. Но если почитать описание fwrite, то она всегда может вернуться раньше, отправив только часть данных. Надо проверять результат, который она возвращает, там есть много вариантов:
- отправлены все данные
- отправлены не все данные
- произошла ошибка
То есть надо читать мануал.
> # Вот эту часть не понимаю - зачем вообще она нужна, но если её убрать то мне всегда вместе с данными с
> # сервера приходят и заголовки, которые мне не нужны.
Изучи протокол HTTP, у меня есть урок: https://github.com/codedokode/pasta/blob/master/network/http.md
Тут тоже написано неправильно, кстати, надо проверять результат fgets. И опять же прочесть мануал по ней.
В общем, для всех функций, которые могут возвращать разные результаты, надо их проверять, не произошло ли ошибки. И изучить сам протокол HTTP сначала.
>>31251
Открой stdin или используй константу STDIN и читай из этого потока: http://php.net/manual/ru/features.commandline.io-streams.php
Ну и изучи саму идею потоков ввода-вывода.
Должен направлять, посмотри отладчиком в браузере (Ctrl + Shift + I) на вкладке Network, какие заголовки отдает сервер.
>>30056
>>31288
> ЗАДАЧА: сделать отправку данных на сервер через fsockopen, то есть используя только стандартные возможности php
Почему нельзя использовать Guzzle?
> # С помощью @ подавляю ошибки fsockopen и возвращаю пустую $data
Это плохо, так как мы не узнаем причину ошибки. А чтобы нормально работать с ошибками, лучше всего использовать исключения: https://github.com/codedokode/pasta/blob/master/php/exceptions.md
> # Какая разница между timeout в fsockopen и этой настройкой? Как правильно сделать?
Надо читать мануал, думаю, в timeout ставится таймаут на установку TCP-соединения с сервером, а тут таймаут на ожидание пакета данных.
> fwrite($fp, $head);
Тут ошибка. Ты почему-то думаешь, что все данные отправятся за один запрос. Но если почитать описание fwrite, то она всегда может вернуться раньше, отправив только часть данных. Надо проверять результат, который она возвращает, там есть много вариантов:
- отправлены все данные
- отправлены не все данные
- произошла ошибка
То есть надо читать мануал.
> # Вот эту часть не понимаю - зачем вообще она нужна, но если её убрать то мне всегда вместе с данными с
> # сервера приходят и заголовки, которые мне не нужны.
Изучи протокол HTTP, у меня есть урок: https://github.com/codedokode/pasta/blob/master/network/http.md
Тут тоже написано неправильно, кстати, надо проверять результат fgets. И опять же прочесть мануал по ней.
В общем, для всех функций, которые могут возвращать разные результаты, надо их проверять, не произошло ли ошибки. И изучить сам протокол HTTP сначала.
>>31251
Открой stdin или используй константу STDIN и читай из этого потока: http://php.net/manual/ru/features.commandline.io-streams.php
Ну и изучи саму идею потоков ввода-вывода.
>Почему нельзя использовать Guzzle?
Потому что не нужны зависимости лишние. Этот метод будет в классе, который предполагается подключать к сайтам клиентов.
И почему для такой простой задачи ты советуешь огромный guzzle, а не curl тогда уж?
Тогда тем более надо сделать проверки всех результатов и обработку ошибок. А то ошибка произойдет - и никто не разберется почему.
Ну и я плохо понимаю в чем проблема использовать сторонние библиотеки. Ты хочешь, чтобы все в одном файле было? Тогда можно использовать склейщик (хотя он вызовет проблемы, если у клиента уже подключен Guzzle).
Но вообще, это сложная затея на мой взгляд. Если клиент не использует тот же композер, то скорее всего у него легаси сайт с неизвсетными настройками PHP, неизвестной конфигурацией обработчика ошибок и тд.
Вот посмотри, как Гугл свой клиент API делает: https://github.com/google/google-api-php-client
Там в зависимостях есть кстати Guzzle.
Зато все с ООП и гибко.
И у Яндекса Guzzle есть: https://github.com/nixsolutions/yandex-php-library
И кстати, да, curl или file_get_contents в твоем случае лучше бы подошел.
Вот я тебе (и другому любителю писать велосипеды) еще такой вопрос задам: а что, если с сервера приходит HTML в формате chunked ? Вы тоже его будет сами разбирать своим велосипедом? А поддержку gzip?
Ничего с сервера в формате chunked приходить не будет. Сервер будет наш, посылать будет в ответ строку определённого формата. С клиента же должна уходить некоторая информация, в том числе сессионные переменные.
Да, важно, чтобы не было лишних зависимостей, класс этот простой, будет представлять из себя один файл - чем проще, тем лучше, потому что скорее всего клиенты будут подключать его сами - втыкать будут в индексный файл. Не думаю, что им захочется возиться с установкой композера и зависимостей.
Спасибо. Сделаю, видимо, с помощью file_get_contents.
https://ideone.com/SjLcUJ
Я не пойму, мое решение норм или нет? Просто все, что я нагуглил выглядит иначе.
там есть компонент symfony cache. это по сути такая обертка на memcached или другой кэш-драйвер, который мы выберем. это понятно
но что за компонент управляет кэшом, который кладет скомпилированные твиги и аннотации в var/cache? где его настройки? это тот же компонент или часть frameworkbundle? как понять логику прогрева кэша - если у меня для каждого пользователя должен быть уникальный csrf-токен, он будет сгенерирован при прогреве? как этим управлять?
и главный вопрос: это вообще можно называть кэшом или это правильнее назвать чем-то типа компилятора из кода фреймворка в raw php-код?
буду также благодарен, если кто-то скинет ссылки где про это почитать. я искал, но не нашел.
Еще вопрос, а что если ивент содержит вложенные классы Reminder, которые тоже нужно сохранить. Пусть родительский EventMapper проверяет наличие "детей" и сам создает ReminderMapper и вызывает ReminderMapper->insertReminders(Reminders)? Или это забота контроллера, вытащить детей из родителя, и для каждого класса создать соответствующий мэппер?
И похожая ситуация, нужно трансформировать Event из класса в json определенной структуры. Event содержит дочерние классы Reminder. Есть соответствующие мэпперы для них. Должен ли родитель проверять наличие детей и создавать мапперы для них или вынести это в код, который создает родительский мэппер, например создать супер класс Mapper, который уже достает детей из родителей и для всех создает нужные мэпперы?
Я читаю это вот всё из треда и про себя думаю. Господи Как же ты хорошь. ты знаешь про обьекты, ты определаешь их типы, ты сохранаешь ивенты. И хочешь это многократно делать. Как же ты по сравнению со мной хорошь. Я ведь только начал путь. Я ведь только начинаю айфоны и айпады, я только начинаю оп задачки, а ты уже на вершине. Смогу ли я достичь такого мегамонстрячества?
Сорян за оффтоп. Накипело всё.
Да бро, сможешь, продолжай заниматься, уже после задачи про департаменты ты будешь знать про объекты и их типы. Я верю в тебя!
> который кладет скомпилированные твиги
Это сам твиг делает, и бандл Симфони только задает настройки для него вроде пути к папке.
> и аннотации в var/cache
О каких аннотациях речь? Если о Доктриновских, то это делает сама Доктрина. Если об аннотациях контроллеров, то думаю, надо искать где-то в FrameworkBundle или по коду, где они ищутся.
> как понять логику прогрева кэша - если у меня для каждого пользователя должен быть уникальный csrf-токен, он будет сгенерирован при прогреве? как этим управлять?
"прогревом кеша" называется генерация симфониевских кешей (например создание компилированной версии DI контейнера или компилированной версии роутера или прокси-классов для доктрины или твиг-шаблонов) при вызове команды cache:warmup. На продакшене это делается вызововом команды, на dev кеш генерируется и обновляется сам при обновлении любого из файлов (например конфига), на основе которого он сгенерирован.
Прогрев кеша не относится к каким-то поьзовательским кешам и твой токен тут не при чем.
В коде можно искать прогрев кеша, изучив команду https://github.com/symfony/framework-bundle/blob/master/Command/CacheWarmupCommand.php :
Например, в FrameworkBundle есть набор cache warmers, можно глянуть их: https://github.com/symfony/framework-bundle/tree/master/CacheWarmer Я не уверен, но может другие бандлы добаляют свои вармеры. Можно попробовать поискать их поиском по файлам у себя.
Вообще, я вроде писал про кеши в Симфони, но не могу найти пост, продублирую тут.
1) кешер опкода (например, opcache) - не часть Симфони, но крайне рекомендуется, если вам важна производительность. Нужно включить. На дев настраиваем revalidate_freq (частота проверки времени модификации файла) низким 1-2 секунды, на продакшене можно настроить его на 1-2-3 минуты, и сбрасывать кеш после деплоя скриптом.
2) Кеш DI контейнера и роутера
Симфони читает конфиги бандлов и пользователя, и создает компилированную версию DI контейнера (то есть PHP класс со всеми вписанными в него настройками и сервисами из контейнера) и роутера (PHP класс, где роуты превращены в код разбора URL на основе preg_match, а также класс генератора URL).
Просто посмотри эти классы в var/cache, это будет лучше любого объяснения. Имена классов вроде devUrlMatcher, devDEbugProjectContainer если я не путаю.
На проде это делается вручную при вызове warmup, на dev эти кеши генерируются и обновляются полност ью сами. Код использования этих кешей можно найти если смотреть тут: https://github.com/symfony/http-kernel/blob/master/Kernel.php#L121 и далее функции вроде
- initializeContainer: https://github.com/symfony/http-kernel/blob/master/Kernel.php#L449
- buildContainer https://github.com/symfony/http-kernel/blob/master/Kernel.php#L591
Заметь, что бандлы и ты сам можешь влиять на процесс компиляции контейнера с помощью классов CompilerPass. Это описано в доках:
- https://symfony.com/doc/current/components/dependency_injection/workflow.html
- https://symfony.com/doc/current/components/dependency_injection/compilation.html
- https://knpuniversity.com/screencast/symfony-journey-di/symfony-builds-the-container
Обрати внимание, что там есть бандлы и компоненты. Компоненты Симфони вроде DI Container - это независимые от фреймворка части, которые можно использовать без него, а бандлы - это именно части фреймворка. Контейнер сделан именно в виде отдельного компонента.
Прогрев роутера надо искать где-то начиная отсюда: https://github.com/symfony/framework-bundle/blob/master/Routing/Router.php (и смотреть класс-предок тоже).
3) Кеш шаблонов твига
Твиг компилирует шаблоны в php-файлы. В дев-версии это делается автоматически, в продакшене командой warmup. Подробности надо искать в самом твиге:
- в прогревальщике кеша шаблонов https://github.com/symfony/twig-bundle/blob/master/CacheWarmer/TemplateCacheWarmer.php
- в компоненте твига, в процессе загрузки шаблона https://github.com/twigphp/Twig/blob/2.x/lib/Twig/Environment.php#L331
Обрати внимание, что есть твиг - независимый компонент, и есть бандл TwigBundle, часть Симфони, которая интегрирует его в фреймворк. Не путай их.
4) Кеш аннотаций доктрины
Доктрина кеширует аннотации из сущностей в php-файлы (которые затем кешируются в opcache). ПРинцип генерации тот же, на продакшене явно, на dev - автоматически при изменении исходных файлов.
5) Прокси-классы Доктрины
Нужны для реализации ленивой загрузки сущностей из БД. На проде генерируются при прогреве и сохраняются как php файлы, на dev вроде бы генерируются на лету в памяти и не сохраняются.
6) Кеш DQL-запросов Доктрины и кеш метаданных сущностей
DQL-запросы надо конвертировать в SQL, это требует время и потому результат конвертирования кешируется. По моему, в Apc.
Это наверно не все кеши, остальные надо искать разбором кода Симфони.
> и главный вопрос: это вообще можно называть кэшом или это правильнее назвать чем-то типа компилятора из кода фреймворка в raw php-код?
Можно назвать кешем.
> который кладет скомпилированные твиги
Это сам твиг делает, и бандл Симфони только задает настройки для него вроде пути к папке.
> и аннотации в var/cache
О каких аннотациях речь? Если о Доктриновских, то это делает сама Доктрина. Если об аннотациях контроллеров, то думаю, надо искать где-то в FrameworkBundle или по коду, где они ищутся.
> как понять логику прогрева кэша - если у меня для каждого пользователя должен быть уникальный csrf-токен, он будет сгенерирован при прогреве? как этим управлять?
"прогревом кеша" называется генерация симфониевских кешей (например создание компилированной версии DI контейнера или компилированной версии роутера или прокси-классов для доктрины или твиг-шаблонов) при вызове команды cache:warmup. На продакшене это делается вызововом команды, на dev кеш генерируется и обновляется сам при обновлении любого из файлов (например конфига), на основе которого он сгенерирован.
Прогрев кеша не относится к каким-то поьзовательским кешам и твой токен тут не при чем.
В коде можно искать прогрев кеша, изучив команду https://github.com/symfony/framework-bundle/blob/master/Command/CacheWarmupCommand.php :
Например, в FrameworkBundle есть набор cache warmers, можно глянуть их: https://github.com/symfony/framework-bundle/tree/master/CacheWarmer Я не уверен, но может другие бандлы добаляют свои вармеры. Можно попробовать поискать их поиском по файлам у себя.
Вообще, я вроде писал про кеши в Симфони, но не могу найти пост, продублирую тут.
1) кешер опкода (например, opcache) - не часть Симфони, но крайне рекомендуется, если вам важна производительность. Нужно включить. На дев настраиваем revalidate_freq (частота проверки времени модификации файла) низким 1-2 секунды, на продакшене можно настроить его на 1-2-3 минуты, и сбрасывать кеш после деплоя скриптом.
2) Кеш DI контейнера и роутера
Симфони читает конфиги бандлов и пользователя, и создает компилированную версию DI контейнера (то есть PHP класс со всеми вписанными в него настройками и сервисами из контейнера) и роутера (PHP класс, где роуты превращены в код разбора URL на основе preg_match, а также класс генератора URL).
Просто посмотри эти классы в var/cache, это будет лучше любого объяснения. Имена классов вроде devUrlMatcher, devDEbugProjectContainer если я не путаю.
На проде это делается вручную при вызове warmup, на dev эти кеши генерируются и обновляются полност ью сами. Код использования этих кешей можно найти если смотреть тут: https://github.com/symfony/http-kernel/blob/master/Kernel.php#L121 и далее функции вроде
- initializeContainer: https://github.com/symfony/http-kernel/blob/master/Kernel.php#L449
- buildContainer https://github.com/symfony/http-kernel/blob/master/Kernel.php#L591
Заметь, что бандлы и ты сам можешь влиять на процесс компиляции контейнера с помощью классов CompilerPass. Это описано в доках:
- https://symfony.com/doc/current/components/dependency_injection/workflow.html
- https://symfony.com/doc/current/components/dependency_injection/compilation.html
- https://knpuniversity.com/screencast/symfony-journey-di/symfony-builds-the-container
Обрати внимание, что там есть бандлы и компоненты. Компоненты Симфони вроде DI Container - это независимые от фреймворка части, которые можно использовать без него, а бандлы - это именно части фреймворка. Контейнер сделан именно в виде отдельного компонента.
Прогрев роутера надо искать где-то начиная отсюда: https://github.com/symfony/framework-bundle/blob/master/Routing/Router.php (и смотреть класс-предок тоже).
3) Кеш шаблонов твига
Твиг компилирует шаблоны в php-файлы. В дев-версии это делается автоматически, в продакшене командой warmup. Подробности надо искать в самом твиге:
- в прогревальщике кеша шаблонов https://github.com/symfony/twig-bundle/blob/master/CacheWarmer/TemplateCacheWarmer.php
- в компоненте твига, в процессе загрузки шаблона https://github.com/twigphp/Twig/blob/2.x/lib/Twig/Environment.php#L331
Обрати внимание, что есть твиг - независимый компонент, и есть бандл TwigBundle, часть Симфони, которая интегрирует его в фреймворк. Не путай их.
4) Кеш аннотаций доктрины
Доктрина кеширует аннотации из сущностей в php-файлы (которые затем кешируются в opcache). ПРинцип генерации тот же, на продакшене явно, на dev - автоматически при изменении исходных файлов.
5) Прокси-классы Доктрины
Нужны для реализации ленивой загрузки сущностей из БД. На проде генерируются при прогреве и сохраняются как php файлы, на dev вроде бы генерируются на лету в памяти и не сохраняются.
6) Кеш DQL-запросов Доктрины и кеш метаданных сущностей
DQL-запросы надо конвертировать в SQL, это требует время и потому результат конвертирования кешируется. По моему, в Apc.
Это наверно не все кеши, остальные надо искать разбором кода Симфони.
> и главный вопрос: это вообще можно называть кэшом или это правильнее назвать чем-то типа компилятора из кода фреймворка в raw php-код?
Можно назвать кешем.
> У меня есть объекты Event и мэппер EventMapper, в котором есть метод Insert для сохранения одного ивента. Если я хочу сохранить несколько, нужно сделать метод вроде InsertEvents(array $events), или для каждого ивента создавать новый мэппер?
Маппер по логике должен быть в одном экземпляре. Ты либо несколько раз вызываешь Insert, либо делаешь метод InsertMany и вызываешь его один раз.
Вообще, классы часто делят на "сущности", которых может быть много экземпляров и "сервисов", которые существуют в одном экземпляре и не имеют состояния.
> Еще вопрос, а что если ивент содержит вложенные классы Reminder, которые тоже нужно сохранить. Пусть родительский EventMapper проверяет наличие "детей" и сам создает ReminderMapper
Маппер точно не должен заниматься созданием других объектов-мапперов, это задача каких-то внешних классов, например, фабрики мапперов:
$this->mapperFactory->getMapperFor(Reminder::class);
Фабрику можно внедрить в маппер через DI. Подумай на досуге, почему я не предлагаю вместо фабрики внедрить в маппер сразу DI контейнер.
> Или это забота контроллера, вытащить детей из родителя, и для каждого класса создать соответствующий мэппер?
Зависит от выбранного тобой подхода. Кстати, Доктрина все это делает сама.
> Есть соответствующие мэпперы для них. Должен ли родитель проверять наличие детей и создавать мапперы для них
Лучше фабрику. Если класс занимается конвертацией в JSON, не его задача создавать другие классы.
>>32777
Сможешь, но надо изучать все последовательно - если ты сейчас возьмешься за мапперы, то можешь запутаться. Но если тебе хочется глянуть одним глазком, то:
- в учебнике на http://codedokode.github.io/phpbook есть глава про ООП, что такое классы и объекты
- в сборнике паст есть урок про ООП-работу с БД и там описано что такое маппер: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md (если ты не знаком с SQL и с драйверами БД вроде PDO то пока будет сложновато понять)
Наш тред всему этому научит.
> У меня есть объекты Event и мэппер EventMapper, в котором есть метод Insert для сохранения одного ивента. Если я хочу сохранить несколько, нужно сделать метод вроде InsertEvents(array $events), или для каждого ивента создавать новый мэппер?
Маппер по логике должен быть в одном экземпляре. Ты либо несколько раз вызываешь Insert, либо делаешь метод InsertMany и вызываешь его один раз.
Вообще, классы часто делят на "сущности", которых может быть много экземпляров и "сервисов", которые существуют в одном экземпляре и не имеют состояния.
> Еще вопрос, а что если ивент содержит вложенные классы Reminder, которые тоже нужно сохранить. Пусть родительский EventMapper проверяет наличие "детей" и сам создает ReminderMapper
Маппер точно не должен заниматься созданием других объектов-мапперов, это задача каких-то внешних классов, например, фабрики мапперов:
$this->mapperFactory->getMapperFor(Reminder::class);
Фабрику можно внедрить в маппер через DI. Подумай на досуге, почему я не предлагаю вместо фабрики внедрить в маппер сразу DI контейнер.
> Или это забота контроллера, вытащить детей из родителя, и для каждого класса создать соответствующий мэппер?
Зависит от выбранного тобой подхода. Кстати, Доктрина все это делает сама.
> Есть соответствующие мэпперы для них. Должен ли родитель проверять наличие детей и создавать мапперы для них
Лучше фабрику. Если класс занимается конвертацией в JSON, не его задача создавать другие классы.
>>32777
Сможешь, но надо изучать все последовательно - если ты сейчас возьмешься за мапперы, то можешь запутаться. Но если тебе хочется глянуть одним глазком, то:
- в учебнике на http://codedokode.github.io/phpbook есть глава про ООП, что такое классы и объекты
- в сборнике паст есть урок про ООП-работу с БД и там описано что такое маппер: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md (если ты не знаком с SQL и с драйверами БД вроде PDO то пока будет сложновато понять)
Наш тред всему этому научит.
>Фабрику можно внедрить в маппер через DI. Подумай на досуге, почему я не предлагаю вместо фабрики внедрить в маппер сразу DI контейнер.
Спасибо, буду думать
огромное спасибо!
получается, что это можно назвать кэшем, т.к. кэш - это некий буфер между системой и запросом, но в то же время это и компиляция конфигов с аннотациями и прочим. меня само слово "кэш" и немного смутило, т.к. есть еще symfony/cache, а еще FrameworkBundle\HttpCache
Кеш это не некий буфер. Это хранилище для данных, которые требуют больших затрат на вычисление.
>Тут стоит просто поставить себе образец Symfony приложения (например https://github.com/symfony/demo/ ) и смотреть код, начиная с public/index.php.
Я смотрел, но в Get Started ничего не говориться о таком коде. Это же автоматически создается?
>Вообще, классы часто делят на "сущности", которых может быть много экземпляров и "сервисов", которые существуют в одном экземпляре и не имеют состояния.
А свойство с объектом PDO означает, что экземпляр имеет состояние?
>Фабрику можно внедрить в маппер через DI.
вот так?
$jsonMapper = new JsonMapper($container['JsonMapperFactory'])
$dbMapper = new DBMapper($container['DBMapperFactory'])
>внедрить в маппер сразу DI контейнер.
$jsonMapper = new JsonMapper($container)
а внутри $jsonMapper:
$reminderMapper = $this->container['reminderMapper']
>почему я не предлагаю вместо фабрики внедрить в маппер сразу DI контейнер.
Наверное потому, что JsonMapper'y не нужно создавать ничего кроме потомков определенного класса, и передача контейнера означала бы передачу большей ответственности, чем необходимо.
DI контейнер, насколько я понял, это более сложная версия фабрики, которая умеет создавать и инициализировать переданные ей объекты вместе с дополнительными параметрами, которые можно легко изменить.
Речь о Доктрине. Если я делаю LIMIT 30, то в БД это 30 строк, среди которых может быть только одна главная сущность со всеми своими ассоциациями и вторая с неполным набором ассоциаций?
Подскажите, пожалуйста, если у меня код получился рабочим, но у меня, как я понял, "слишком сложный" код, когда решение может быть гораздо проще. Это сильно плохо?
Я всё облазил, всё проверил. Вроде всё правильно, но браузер не перенаправляет на нужную страницу, а просто перезагружает текущую без выведения ошибок.
Однако, если я удалю строку с connection, то всё работает.
Ничем конкретно, потому что надо использовать параметризованные запросы.
Я всячески пытался их PDO что-нибудь слепить. Конечный вариант хоть ошибки выдаёт.
1 вариант - как в демо приложении симфони:
public function showArticle(Article $article): Response
{
return $this->render('article.html.twig', ['article' => $article]);
}
2 вариант (как я сначала написал):
public function showArticle(int $id): Response
{
$repo = $this->getDoctrine()->getRepository(Article::class);
$article = $repo->find($id);
if (!$article) {
throw new NotFoundHttpException('The article is not found');
}
return $this->render('article.html.twig', ['article' => $article]);
}
чем второй вариант хуже?
Что за ошибки?
Вот простой и понятный пример использования pdo
https://phpdelusions.net/pdo
Внимательно изучи и попробуй разобраться что к чему.
>interval это интервал, чаще которого нельзя посылать запросы к одному домену.
И в чем его смысл, если этот интервал может истечь до завершения текущего запроса?
>я не сталкивался пока с кодом 203, и никто мне не писал про этов Issues
Лол. У меня тут на проекте с посещалкой 4к уников/день месяца два назад, оказывается, отвалилась фича, не покрытая тестами. Багрепорт я получил только вчера. Никто никогда не напишет тебе issue про такие вещи.
>обнаружение припаркованных (то есть потерянных или проданных владельцем) доменов
Обходим все ссылки первый раз. Здесь придется проверить глазками, отдают ли ссылки то, что отдавали ранее. Пишем таймстамп последней проверки, пишем eTag, если имеется, Last-Modified, если имеется, Content-Length, если имеется. Делаем запрос whois, записываем expire-date.
Алгоритм последующих проверок:
Отправляем запрос с Etag / If-Modified-Since. Получаем 304? Ссылка живая.
Делаем запрос. Content-Length прежний? Ссылка живая.
Expire-date < now? Делаем запрос в whois. Домен перерегистрирован? Подозрительность ссылки +1.
Днс поменялись на днс из словаря доменных парковок? Подозрительность ссылки +1.
На странице присутствуют вхождения $domainParkingMarkers = ['parking', 'for sale', 'domain owner']? Подозрительность ссылки +1.
site.com/dsfjklsjfklsjdf отдавало 404, а теперь отдает 200, и Content-Length плюс-минус одинаков на любой странице? Подозрительность ссылки +1.
Ответы в твоем же вопросе.
>Другая проблема - некоторые домены не любят ботов (а я честно подписываю User-Agent)
Если 403, либо редирект на локалхост, делаешь второй запрос с юзер-агентом браузера. А вообще веб должен быть доступен для любого клиента, поэтому можешь слать к черту такие ссылки. Btw, если ты претендуешь на честность, тебе нужно уважать robots.txt.
>Третья проблема - проверка ссылок вроде mega.nz/#12345
Ну да, здесь придется писать правила. Btw, ргхост отдает мне 404.
>Надеюсь, что Гузл это сам обработает
Проблемы черных ящиков.
>Странно, мне кажется, что обязательно
>Можешь дать пример страницы, где есть 3xx но это не редирект?
Пожалуйста. Запусти да проверь.
https://pastebin.com/VAmaBpLQ
Ты увидишь "Есть два стула". Редиректа не произойдет.
А еще 304 не редирект.
А еще 305 deprecated.
А еще 306 зарезервирован. А еще все коды, начиная с 309. Ты обязан игнорировать Location у таких кодов.
Итого, безусловных редиректов пять - 301, 302, 303, 307, 308. А у тебя - сотня.
>Ну и как я понимаю, большинство браузеров отредиректит пользователя
Неправильно понимаешь, не отредиректит. Ты споришь со мной, хотя можешь открыть первую ссылку в гугле и почитать RFC.
https://tools.ietf.org/html/rfc7231#section-6.4.1
> The user agent MAY use the Location field value for automatic redirection.
> MAY
>> Сервер не обязан отсылать Content-Type.
>Не уверен.
А RFC уверен.
https://tools.ietf.org/html/rfc7231#section-3.1.1.5
> A sender that generates a message containing a payload body SHOULD
> generate a Content-Type header field in that message unless the
> intended media type of the enclosed representation is unknown to the
> sender. If a Content-Type header field is not present, the recipient
> MAY either assume a media type of "application/octet-stream"
> ([RFC2046], Section 4.5.1) or examine the data to determine its type.
Напомню, что SHOULD это не MUST. Должен, но не обязан. Юзер-агент может посмотреть данные, чтобы определить тип.
>Мне не пришлось писать свой HTTP клиент
file_get_contents
>объекты для представления HTTP запросов и ответов
Для запросов из коробки stream context. Для ответов обертка хидеров и контента пишется за 5 минут.
>Не пришлось изучать кучу тонкостей, про которые ты написал (про 203 я например не знал)
Одну секунду, причем тут 203? Газл тебе возвращает ответ, а дальше, чем делать с этими кодами - твой геморрой. Газл тебя от этого не избавляет.
>4 строчки про то, зачем писать HTTP-клиент
Действительно зачем, если есть file_get_contents, который даже из коробки, мать его, через stream notification callback может рассказать тебе о переадресациях согласно RFC, и так же из коробки ты можешь запретить ходить по переадресациям.
Но лучше я возьму Газл, он лучше, и напишу свой велосипед, предполагая, что все 3хх коды - переадресации. Вместо использования того, что решает задачу из коробки! Ты не поверишь, можно даже подписаться на STREAM_NOTIFY_MIME_TYPE_IS! В момент получения Content-Type сработает твой коллбэк! Из коробки!
В итоге я только укрепляюсь во мнении, что ты бездумно используешь черные ящики лишь потому, что тебе лень разобраться в протоколе, который общается обычным ASCII-текстом.
>>32460
>недружелюбно по отношению к серверу
Лол! Серьезно?! TCP вообще похуй, когда ты закроешь сокет. Закрыл, досвидос. Ах да, если ты не знал, сервер обязан выполнить все те же действия при запросе HEAD, что и при запросе GET. Даже сходить куда-нибудь в MySQL-базу за океан. Потому что код не знает, вдруг, если в базе небо == аллаху, то где-то дальше добавится заголовок X-Allah: Bicycle.
А вот контента ты не получишь. Представляешь как недружелюблюбно?
>тут для Guzzle 6
>можно костылем передать нужные опции для curl
Лол, да что ж тебя на подвиги-то тянет. Из коробки (повторяю - из ко-роб-ки!) можно открыть сокет, функцией stream_get_meta_data прочитать только хидеры и исключительно хидеры, и закрыть сокет! Из коробки! Три строчки кода! fopen, stream_get_meta_data, fclose!
>>32462
>Нет, чтобы получить просто заголовки, тебе придется писать код, чтобы добавить таймаут, еще какой-то код и так далее.
Это уже не смешно. Вы чего, стандартную либу не знаете? Три строки кода, три! fopen, stream_get_meta_data, fclose! Таймаут задается параметром в stream context!
>он умеет делать так: http://example.com/a/b + ../file.txt = http://example.com/file.txt
Да ладно!
if (strpos($href, '/') !== 0) { $url = realpath(dirname('http://example.com/a/b') . '/' . $url); } else { // да, для абсолютного пути придется пересобрать хост через parse_url с учетом возможного порта и даже логина-пароля }
Минута программирования. Нет, надо подтянуть библиотеку.
Кстати, спешу огорчить. Есть тег <base>, который переопределяет, от какой директории строить url. Твой скрипт это учитывает? А может, учитывает Газл? Ой нет, он просто по ссылочкам ходит. Что же делать? Нужно срочно искать библиотеку!
> Не вижу в чем выгода тратить время на переизобретение того, что уже написано.
Изобретение чего? Конкатенации директорий? Тебе нужен jQuery, чтобы сложить 2 + 2?
>И что я теряю, используя готовую библиотеку.
Если в готовой библиотеке находится уязвимость, тоби пизда. У тебя тоже могут быть уязвимости, но здесь работает теория неуловимого Джо - ты никому не нужен.
Вы просто клепаете веб-приложушки из готовых модулей, а за моими плечами база. Мои абстракции - это голый PHP, ваши - библиотечки, чтобы склеивать директории.
Если мне дать микроволновку, где будет крутиться Java Micro Edition и в либе только сокеты, я смогу сделать http-реквест и получить ответ, а вы не сможете ничего.
>interval это интервал, чаще которого нельзя посылать запросы к одному домену.
И в чем его смысл, если этот интервал может истечь до завершения текущего запроса?
>я не сталкивался пока с кодом 203, и никто мне не писал про этов Issues
Лол. У меня тут на проекте с посещалкой 4к уников/день месяца два назад, оказывается, отвалилась фича, не покрытая тестами. Багрепорт я получил только вчера. Никто никогда не напишет тебе issue про такие вещи.
>обнаружение припаркованных (то есть потерянных или проданных владельцем) доменов
Обходим все ссылки первый раз. Здесь придется проверить глазками, отдают ли ссылки то, что отдавали ранее. Пишем таймстамп последней проверки, пишем eTag, если имеется, Last-Modified, если имеется, Content-Length, если имеется. Делаем запрос whois, записываем expire-date.
Алгоритм последующих проверок:
Отправляем запрос с Etag / If-Modified-Since. Получаем 304? Ссылка живая.
Делаем запрос. Content-Length прежний? Ссылка живая.
Expire-date < now? Делаем запрос в whois. Домен перерегистрирован? Подозрительность ссылки +1.
Днс поменялись на днс из словаря доменных парковок? Подозрительность ссылки +1.
На странице присутствуют вхождения $domainParkingMarkers = ['parking', 'for sale', 'domain owner']? Подозрительность ссылки +1.
site.com/dsfjklsjfklsjdf отдавало 404, а теперь отдает 200, и Content-Length плюс-минус одинаков на любой странице? Подозрительность ссылки +1.
Ответы в твоем же вопросе.
>Другая проблема - некоторые домены не любят ботов (а я честно подписываю User-Agent)
Если 403, либо редирект на локалхост, делаешь второй запрос с юзер-агентом браузера. А вообще веб должен быть доступен для любого клиента, поэтому можешь слать к черту такие ссылки. Btw, если ты претендуешь на честность, тебе нужно уважать robots.txt.
>Третья проблема - проверка ссылок вроде mega.nz/#12345
Ну да, здесь придется писать правила. Btw, ргхост отдает мне 404.
>Надеюсь, что Гузл это сам обработает
Проблемы черных ящиков.
>Странно, мне кажется, что обязательно
>Можешь дать пример страницы, где есть 3xx но это не редирект?
Пожалуйста. Запусти да проверь.
https://pastebin.com/VAmaBpLQ
Ты увидишь "Есть два стула". Редиректа не произойдет.
А еще 304 не редирект.
А еще 305 deprecated.
А еще 306 зарезервирован. А еще все коды, начиная с 309. Ты обязан игнорировать Location у таких кодов.
Итого, безусловных редиректов пять - 301, 302, 303, 307, 308. А у тебя - сотня.
>Ну и как я понимаю, большинство браузеров отредиректит пользователя
Неправильно понимаешь, не отредиректит. Ты споришь со мной, хотя можешь открыть первую ссылку в гугле и почитать RFC.
https://tools.ietf.org/html/rfc7231#section-6.4.1
> The user agent MAY use the Location field value for automatic redirection.
> MAY
>> Сервер не обязан отсылать Content-Type.
>Не уверен.
А RFC уверен.
https://tools.ietf.org/html/rfc7231#section-3.1.1.5
> A sender that generates a message containing a payload body SHOULD
> generate a Content-Type header field in that message unless the
> intended media type of the enclosed representation is unknown to the
> sender. If a Content-Type header field is not present, the recipient
> MAY either assume a media type of "application/octet-stream"
> ([RFC2046], Section 4.5.1) or examine the data to determine its type.
Напомню, что SHOULD это не MUST. Должен, но не обязан. Юзер-агент может посмотреть данные, чтобы определить тип.
>Мне не пришлось писать свой HTTP клиент
file_get_contents
>объекты для представления HTTP запросов и ответов
Для запросов из коробки stream context. Для ответов обертка хидеров и контента пишется за 5 минут.
>Не пришлось изучать кучу тонкостей, про которые ты написал (про 203 я например не знал)
Одну секунду, причем тут 203? Газл тебе возвращает ответ, а дальше, чем делать с этими кодами - твой геморрой. Газл тебя от этого не избавляет.
>4 строчки про то, зачем писать HTTP-клиент
Действительно зачем, если есть file_get_contents, который даже из коробки, мать его, через stream notification callback может рассказать тебе о переадресациях согласно RFC, и так же из коробки ты можешь запретить ходить по переадресациям.
Но лучше я возьму Газл, он лучше, и напишу свой велосипед, предполагая, что все 3хх коды - переадресации. Вместо использования того, что решает задачу из коробки! Ты не поверишь, можно даже подписаться на STREAM_NOTIFY_MIME_TYPE_IS! В момент получения Content-Type сработает твой коллбэк! Из коробки!
В итоге я только укрепляюсь во мнении, что ты бездумно используешь черные ящики лишь потому, что тебе лень разобраться в протоколе, который общается обычным ASCII-текстом.
>>32460
>недружелюбно по отношению к серверу
Лол! Серьезно?! TCP вообще похуй, когда ты закроешь сокет. Закрыл, досвидос. Ах да, если ты не знал, сервер обязан выполнить все те же действия при запросе HEAD, что и при запросе GET. Даже сходить куда-нибудь в MySQL-базу за океан. Потому что код не знает, вдруг, если в базе небо == аллаху, то где-то дальше добавится заголовок X-Allah: Bicycle.
А вот контента ты не получишь. Представляешь как недружелюблюбно?
>тут для Guzzle 6
>можно костылем передать нужные опции для curl
Лол, да что ж тебя на подвиги-то тянет. Из коробки (повторяю - из ко-роб-ки!) можно открыть сокет, функцией stream_get_meta_data прочитать только хидеры и исключительно хидеры, и закрыть сокет! Из коробки! Три строчки кода! fopen, stream_get_meta_data, fclose!
>>32462
>Нет, чтобы получить просто заголовки, тебе придется писать код, чтобы добавить таймаут, еще какой-то код и так далее.
Это уже не смешно. Вы чего, стандартную либу не знаете? Три строки кода, три! fopen, stream_get_meta_data, fclose! Таймаут задается параметром в stream context!
>он умеет делать так: http://example.com/a/b + ../file.txt = http://example.com/file.txt
Да ладно!
if (strpos($href, '/') !== 0) { $url = realpath(dirname('http://example.com/a/b') . '/' . $url); } else { // да, для абсолютного пути придется пересобрать хост через parse_url с учетом возможного порта и даже логина-пароля }
Минута программирования. Нет, надо подтянуть библиотеку.
Кстати, спешу огорчить. Есть тег <base>, который переопределяет, от какой директории строить url. Твой скрипт это учитывает? А может, учитывает Газл? Ой нет, он просто по ссылочкам ходит. Что же делать? Нужно срочно искать библиотеку!
> Не вижу в чем выгода тратить время на переизобретение того, что уже написано.
Изобретение чего? Конкатенации директорий? Тебе нужен jQuery, чтобы сложить 2 + 2?
>И что я теряю, используя готовую библиотеку.
Если в готовой библиотеке находится уязвимость, тоби пизда. У тебя тоже могут быть уязвимости, но здесь работает теория неуловимого Джо - ты никому не нужен.
Вы просто клепаете веб-приложушки из готовых модулей, а за моими плечами база. Мои абстракции - это голый PHP, ваши - библиотечки, чтобы склеивать директории.
Если мне дать микроволновку, где будет крутиться Java Micro Edition и в либе только сокеты, я смогу сделать http-реквест и получить ответ, а вы не сможете ничего.
Ой, мне нужно признать обосрамс. Ложился спать и вспомнил про функцию get_headers. Так что хедеры получаются в пхп одной строкой.
Он для введенной команды находит мануал и показывает объяснение каждой опции, например: https://explainshell.com/explain?cmd=x11vnc+-rfbport+4544+-rfbauth+/tmp/vncpass+-display+:44+-forever+-auth+/tmp/xvfb.auth
Также, вы можете щелкнуть правой кнопкой по полю поиска там, выбрать "добавить как поисковую систему", задать ключевое слово и открывать подсказку прямо из адресной строки браузера.
Добавил также эту информацию в урок по cli.
Годнота. Спасибо.
Не понял смысл этого сайта. Там же просто выводится строка из справки. Не проще ли и не полезней, раз уж вы ИЗУЧАЕТЕ линукс, читать справку по программе programma_name --help?
> И в чем его смысл, если этот интервал может истечь до завершения текущего запроса?
Смысл в том, чтобы не перегружать сторонний сервер запросами и тем самым снизить вероятность получения бана моего бота. Я хочу, чтобы запросы к определенному домену отправлялись бы не чаще, чем раз в N (сейчас N=3) секунд, если интервал будет больше - ничего страшного.
По факту, это да, интервал не между окончанием одного запроса и началом следующего, а между началом одного и второго. Пусть пока так будет.
> Никто никогда не напишет тебе issue про такие вещи
Значит, это никого не беспокоит.
> таймстамп последней проверки, пишем eTag, если имеется
Это будет вызывать ложные срабатывания, особенно если контент динамический и last modified нету или он постоянно увеличивается. Content-length будет меняться при изменении где-то в шапке, сайдбаре и тд.
У меня кстати была мысль интереснее: многие припаркованные домены подгружают ссылки через JS и их можно детектирвоать по отсутствию (или маленькому количеству) текста в HTML.
Про whois - да, вариант, хотя это требует подключать стороннюю библиотеку и разбираться с протоколом whois.
> Домен перерегистрирован? Подозрительность ссылки +1.
Это надо где-то держать историю проверок домена. Это снижает автономность инструмента.
> Днс поменялись на днс из словаря доменных парковок? Подозрительность ссылки +1.
Согласен, это можно.
> site.com/dsfjklsjfklsjdf отдавало 404, а теперь отдает 200, и Content-Length плюс-минус одинаков на любой странице?
Да, это тоже рабочий вариант, только не хочется слать запросы подряд на все домены, это надо как-то сначала отобрать "подозрительные" ссылки и их уже тщательнее проверять.
> А вообще веб должен быть доступен для любого клиента, поэтому можешь слать к черту такие ссылки
Не, я не хочу прикидываться браузером. Да и тот же cloudflare все равно не пропустит браузер без JS.
> Btw, если ты претендуешь на честность, тебе нужно уважать robots.txt.
Есть в TODO.
> Пожалуйста. Запусти да проверь.
> Ты увидишь "Есть два стула".
Это интересно, но я пока с такой проблемой все равно не сталкивался. Так да, можно повнимательнее разобрать 3xx коды.
> Из коробки! Три строчки кода! fopen, stream_get_meta_data, fclose!
А где объекты Response? Где разбор заголовков? Где задание корневых SSL-сертификатов? В Guzzle я просто пишу $response->getHeader() или $response->getStatusCode(), корневые сертификаты получаю другой библиотекой.
Ты бы код Гуззле открыл и посмотрел, что там понаписано. Она конечно местами переусложненная, но свои задачи решает, так что я не против.
> стандартную либу не знаете?
Она такая страшная, что к ней подходить лишний раз не хочется. И к тому же в исключения не умеет.
>>он умеет делать так: http://example.com/a/b + ../file.txt = http://example.com/file.txt
> Да ладно!
> if (strpos($href, '/') !== 0) { $url = realpath(dirname('http://example.com/a/b') . '/' . $url); } else { // да, для абсолютного пути придется пересобрать хост через parse_url с учетом возможного порта и даже логина-пароля }
Ну то есть надо изучать RFC про относительные ссылки и писать код. А я могу взять готовый код и ничего не писать. Какая мне выгода выбрать первый вариант? У меня есть вполне конкретные аргументы:
- экономия времени на написании кода и комментариев/документации к нему
- надежда, что код в библиотеке протестирован (в случае с Guzzle, у них есть тесты и подключен CI сервер, проверяющий коммиты)
- надежда, что сообщество будет править баги, закрывать уязвимости и поддерживать библилотеку. Я ничего не делаю, а баги исправляются. Разве это не прекрасно?
А завтра мне может понадобится параллельная отправка запросов (которая вроде как есть в Гуззл), это мне тоже все самому написать?
Какие у тебя есть аргументы за написание велосипеда? Не из серии "мне не нравится" или "надо RFC изучать", а объективные преимущества написания своего велосипеда в данном случае? Что я выигрываю?
> Если в готовой библиотеке находится уязвимость
То может быть, ее исправят без меня.
> Вы просто клепаете веб-приложушки из готовых модулей, а за моими плечами база.
У меня просто ограниченное количество времени.
> Если мне дать микроволновку, где будет крутиться Java Micro Edition и в либе только сокеты, я смогу сделать http-реквест и получить ответ, а вы не сможете ничего.
Я смогу, но не понимаю, зачем мне это нужно.
Вот кстати, я сейчас несколько часов угробил, пытаясь запустить firefox 3.5.19 под xvfb (он падает на старте скорее всего из-за современной версии glib), вот тебе бы, как любителю во всем разбираться, наверно было бы интересно исследовать проблему? Я конечно подумываю просто попрбовать еще другие версии фаерфокса. Или найти способ поставить как-то ему старый glib.
Там все настолько плохо, что даже отладочные символы для этой старой версии непонятно где искать. gdb малополезен, нужно разбираться с breakpad (или брать где-то Visual Studio, хотя дампы линуксовые), причем новый, естественно, не читает старые дампы, а старый еще замучаешься собирать. Про менеджеры пакетов сишники и не слышали (по задумке, надо использовать apt-get, но попробуй им поставь старую версию библиотеки или что-то, чего нет в репозитории). Ох, как просто с PHP работать в сравнении с этим сишно-яваскриптовым монстром.
> И в чем его смысл, если этот интервал может истечь до завершения текущего запроса?
Смысл в том, чтобы не перегружать сторонний сервер запросами и тем самым снизить вероятность получения бана моего бота. Я хочу, чтобы запросы к определенному домену отправлялись бы не чаще, чем раз в N (сейчас N=3) секунд, если интервал будет больше - ничего страшного.
По факту, это да, интервал не между окончанием одного запроса и началом следующего, а между началом одного и второго. Пусть пока так будет.
> Никто никогда не напишет тебе issue про такие вещи
Значит, это никого не беспокоит.
> таймстамп последней проверки, пишем eTag, если имеется
Это будет вызывать ложные срабатывания, особенно если контент динамический и last modified нету или он постоянно увеличивается. Content-length будет меняться при изменении где-то в шапке, сайдбаре и тд.
У меня кстати была мысль интереснее: многие припаркованные домены подгружают ссылки через JS и их можно детектирвоать по отсутствию (или маленькому количеству) текста в HTML.
Про whois - да, вариант, хотя это требует подключать стороннюю библиотеку и разбираться с протоколом whois.
> Домен перерегистрирован? Подозрительность ссылки +1.
Это надо где-то держать историю проверок домена. Это снижает автономность инструмента.
> Днс поменялись на днс из словаря доменных парковок? Подозрительность ссылки +1.
Согласен, это можно.
> site.com/dsfjklsjfklsjdf отдавало 404, а теперь отдает 200, и Content-Length плюс-минус одинаков на любой странице?
Да, это тоже рабочий вариант, только не хочется слать запросы подряд на все домены, это надо как-то сначала отобрать "подозрительные" ссылки и их уже тщательнее проверять.
> А вообще веб должен быть доступен для любого клиента, поэтому можешь слать к черту такие ссылки
Не, я не хочу прикидываться браузером. Да и тот же cloudflare все равно не пропустит браузер без JS.
> Btw, если ты претендуешь на честность, тебе нужно уважать robots.txt.
Есть в TODO.
> Пожалуйста. Запусти да проверь.
> Ты увидишь "Есть два стула".
Это интересно, но я пока с такой проблемой все равно не сталкивался. Так да, можно повнимательнее разобрать 3xx коды.
> Из коробки! Три строчки кода! fopen, stream_get_meta_data, fclose!
А где объекты Response? Где разбор заголовков? Где задание корневых SSL-сертификатов? В Guzzle я просто пишу $response->getHeader() или $response->getStatusCode(), корневые сертификаты получаю другой библиотекой.
Ты бы код Гуззле открыл и посмотрел, что там понаписано. Она конечно местами переусложненная, но свои задачи решает, так что я не против.
> стандартную либу не знаете?
Она такая страшная, что к ней подходить лишний раз не хочется. И к тому же в исключения не умеет.
>>он умеет делать так: http://example.com/a/b + ../file.txt = http://example.com/file.txt
> Да ладно!
> if (strpos($href, '/') !== 0) { $url = realpath(dirname('http://example.com/a/b') . '/' . $url); } else { // да, для абсолютного пути придется пересобрать хост через parse_url с учетом возможного порта и даже логина-пароля }
Ну то есть надо изучать RFC про относительные ссылки и писать код. А я могу взять готовый код и ничего не писать. Какая мне выгода выбрать первый вариант? У меня есть вполне конкретные аргументы:
- экономия времени на написании кода и комментариев/документации к нему
- надежда, что код в библиотеке протестирован (в случае с Guzzle, у них есть тесты и подключен CI сервер, проверяющий коммиты)
- надежда, что сообщество будет править баги, закрывать уязвимости и поддерживать библилотеку. Я ничего не делаю, а баги исправляются. Разве это не прекрасно?
А завтра мне может понадобится параллельная отправка запросов (которая вроде как есть в Гуззл), это мне тоже все самому написать?
Какие у тебя есть аргументы за написание велосипеда? Не из серии "мне не нравится" или "надо RFC изучать", а объективные преимущества написания своего велосипеда в данном случае? Что я выигрываю?
> Если в готовой библиотеке находится уязвимость
То может быть, ее исправят без меня.
> Вы просто клепаете веб-приложушки из готовых модулей, а за моими плечами база.
У меня просто ограниченное количество времени.
> Если мне дать микроволновку, где будет крутиться Java Micro Edition и в либе только сокеты, я смогу сделать http-реквест и получить ответ, а вы не сможете ничего.
Я смогу, но не понимаю, зачем мне это нужно.
Вот кстати, я сейчас несколько часов угробил, пытаясь запустить firefox 3.5.19 под xvfb (он падает на старте скорее всего из-за современной версии glib), вот тебе бы, как любителю во всем разбираться, наверно было бы интересно исследовать проблему? Я конечно подумываю просто попрбовать еще другие версии фаерфокса. Или найти способ поставить как-то ему старый glib.
Там все настолько плохо, что даже отладочные символы для этой старой версии непонятно где искать. gdb малополезен, нужно разбираться с breakpad (или брать где-то Visual Studio, хотя дампы линуксовые), причем новый, естественно, не читает старые дампы, а старый еще замучаешься собирать. Про менеджеры пакетов сишники и не слышали (по задумке, надо использовать apt-get, но попробуй им поставь старую версию библиотеки или что-то, чего нет в репозитории). Ох, как просто с PHP работать в сравнении с этим сишно-яваскриптовым монстром.
Первый способ требует ведь наличия аннотации для ParamsConverter? А так, используй, что тебе нравится.
>>33245
Зачем у тебя там quote, если ты ничего в БД не вставляешь? Ради чего ты экранируешь текст?
strlen не работает с кириллицей в utf-8, используй mb_strlen: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Перехватывать исключения (try/catch), чтобы распечатать, не нужно - можно просто включить display_errors = 1.
PDO использован неправильно ($category->execute), почитай статью по PDO. А то ощущение, что ты частично наугад код пишешь, так оно не заработает.
Вместо strftime лучше исопльзовать date().
>>33165
У тебя переусложнен код поиска элемента в массиве. ЧТобы найти значение элемента, имея ключ, надо сделать так: $value = $array[$key], цикл городить не надо.
>>33014
Там есть для этого пагинатор, который как-то хитро видоизменяет запрос: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/pagination.html (аналогичные статььи наверно можно найти на русском).
Но я ему не довряю, так как боюсь, что он там нагородит что-то сложное. Проще просто выбирать нужные тебе сущности без джойнов (то есть вместо SELECT x, y просто писать SELECT x). Да, там написано, что с джойном оно должно выбираться быстрее, но ты померяй - я наблюдал ровно обратную ситуацию.
Если тебе не нужны полные сущности (а например только id), то проще вообще SQL запрос сделать.
Первый способ требует ведь наличия аннотации для ParamsConverter? А так, используй, что тебе нравится.
>>33245
Зачем у тебя там quote, если ты ничего в БД не вставляешь? Ради чего ты экранируешь текст?
strlen не работает с кириллицей в utf-8, используй mb_strlen: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Перехватывать исключения (try/catch), чтобы распечатать, не нужно - можно просто включить display_errors = 1.
PDO использован неправильно ($category->execute), почитай статью по PDO. А то ощущение, что ты частично наугад код пишешь, так оно не заработает.
Вместо strftime лучше исопльзовать date().
>>33165
У тебя переусложнен код поиска элемента в массиве. ЧТобы найти значение элемента, имея ключ, надо сделать так: $value = $array[$key], цикл городить не надо.
>>33014
Там есть для этого пагинатор, который как-то хитро видоизменяет запрос: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/pagination.html (аналогичные статььи наверно можно найти на русском).
Но я ему не довряю, так как боюсь, что он там нагородит что-то сложное. Проще просто выбирать нужные тебе сущности без джойнов (то есть вместо SELECT x, y просто писать SELECT x). Да, там написано, что с джойном оно должно выбираться быстрее, но ты померяй - я наблюдал ровно обратную ситуацию.
Если тебе не нужны полные сущности (а например только id), то проще вообще SQL запрос сделать.
> А свойство с объектом PDO означает, что экземпляр имеет состояние?
нет, это не мешает ему быть "сервисом".
> >Фабрику можно внедрить в маппер через DI.
> вот так?
Нет, тогда уж так
$dbMapperFactory = new DBMapper($container['DBMapperFactory']);
>> почему я не предлагаю вместо фабрики внедрить в маппер сразу DI контейнер.
> Наверное потому, что JsonMapper'y не нужно создавать ничего кроме потомков определенного класса, и передача контейнера означала бы передачу большей ответственности, чем необходимо.
Да, и вообще, это нарушение идеи DI container, так как объекты о контейнере знать ничего не должны и не должны от него зависеть.
>>32945
Пользователей.
>>32922
Я думаю, можно просто посмотреть инструкции по установке в symfony-demo, скорее всего надо просто запустить композер и может что-то в конфиге подправить. Ну если ставить обычный шаблон (как тут http://symfony.com/doc/current/setup.html ) то примерно то же получишь. Я думаю, там тоже будет public/index.php и примерно те же классы.
>>33308
Справки бывают огромные, а тут нужные части уже найдены и вырезаны.
> А свойство с объектом PDO означает, что экземпляр имеет состояние?
нет, это не мешает ему быть "сервисом".
> >Фабрику можно внедрить в маппер через DI.
> вот так?
Нет, тогда уж так
$dbMapperFactory = new DBMapper($container['DBMapperFactory']);
>> почему я не предлагаю вместо фабрики внедрить в маппер сразу DI контейнер.
> Наверное потому, что JsonMapper'y не нужно создавать ничего кроме потомков определенного класса, и передача контейнера означала бы передачу большей ответственности, чем необходимо.
Да, и вообще, это нарушение идеи DI container, так как объекты о контейнере знать ничего не должны и не должны от него зависеть.
>>32945
Пользователей.
>>32922
Я думаю, можно просто посмотреть инструкции по установке в symfony-demo, скорее всего надо просто запустить композер и может что-то в конфиге подправить. Ну если ставить обычный шаблон (как тут http://symfony.com/doc/current/setup.html ) то примерно то же получишь. Я думаю, там тоже будет public/index.php и примерно те же классы.
>>33308
Справки бывают огромные, а тут нужные части уже найдены и вырезаны.
-1 это битовая операция https://en.wikipedia.org/wiki/Ones'_complement
Лучше использовать E_ALL.
Посмотреть в живую:
echo decbin(E_ALL) . PHP_EOL;
echo decbin(-1) . PHP_EOL;
У меня случился отпуск. Хочу походить по собеседованиям. Но для этого, для начала, нужно откликнуться на вакансии. Вопрос: с моим уровнем (за полтора года смог немного выучить html, css, js, php, yii, mysql, git) можно откликаться только на самые днищевакансии стажёров, или уже можно чуть повыше? Какой примерно должна быть адекватная вакансия по требованиям и условиям?
Код работающего проекта:
(Из того, что посоветовали на прошлом ревью, успел выполнить только треть, поэтому новых советов пока не прошу.)
Папку scrinshots => screenshots. Просто первое что в глаза бросается. Сразу все "английский на уровне понимания документации" под вопросом.
Ох лол, вот это обосрался. Но вообще да, английский знаю плохо.
походи по собесам, поймешь что нужно будет подучить. я бы пошел на 60к посмотрел (в дс), если совсем не потянешь, то снижать планку. плюс определись, какие технологии тебе интересны и не разбрасывайся на остальные (очевидно в твоем случае это yii).
по проекту, по моему опыту такие проекты на собеседованиях никто особо не смотрят, может поставят галочку в голове типа "учится-интересуется", но вообще всем похуй. еще вариант: могут ткнуть в случайное место, увидеть какой-то один косяк и сделать по нему преждевременные выводы.
если будешь показывать этот проект, удали все ненужные комментарии в коде, их там больше половины от всего проекта. все "было-стало" видно по коммитам, такие комменты бессмысленны. также в качестве коммит-меседжей пишут "добавил штуку такую-то", а не номер версии. еще отформатируй ридми, в одной строке текст и картинка не комильфо.
>scrinshots => screenshots
Исправил.
>>33644
>"было-стало" видно по коммитам, такие комменты бессмысленны
Это где такие комменты? Хотя, наверное есть. Завтра на свежую голову всё прогляжу и удалю лишнее.
>в качестве коммит-меседжей пишут "добавил штуку такую-то", а не номер версии
Ты прав, надо будет начать писать более содержательные месседжи.
>еще отформатируй ридми
Отформатировал.
>я бы пошел на 60к
Окей, от этой цифры и буду отталкиваться.
Откликайся на всё. Я без опыта откликнулся на вакансию на 70к, написал тест, мне еще сказали, что по результатам я опытный мидл, лол. Приняли без вопросов.
Единственно, что я все-таки полупридумал предыдущее место работы. Два года назад написал сайт для организации, прямо как ты, и написал - опыт работы два года, ООО Ромашка.
>Там именно это и написано
Осторожнее с этим дерьмом. У меня было указано то же самое. И мне дали тест на английском. А когда приняли, посадили на мультиязычный проект, где надо писать все строковые литералы на русском, и на английском. Пишу на ломаном английском, тимлид пока не доебывается.
>Это где такие комменты? Хотя, наверное есть. Завтра на свежую голову всё прогляжу и удалю лишнее.
завтра тебя ждет сюрприз
там ничего секретного, просто ОЧЕНЬ много комментариев вида
#$arr1 = 22;
//$arr2 - вчера работало
и прочего. на работе твой код будет проверяться по строчке и по символу (если ты не будешь работать в дизайн-студии, конечно). если есть кодстайл, то по нему ебут даже за переводы строк в неправильных местах. так что учитывай, что это будут смотреть такие вот чуваки.
для джуна это все конечно придирки,
но и возможность заработать плюсик
Уф, анон, ты даже не представляешь, на какую измену я подсел. Думал уже, в репу пробралось что-то из продакшен-версии. А там реальные фамилии, названия фирм заказчиков и прочая ботва. И вроде все данные в базе были, но а вдруг...
Надо и вправду причесать всё хоть как-то. Когда один пишешь, все эти комменты таки помогают. Хотя бы уже тем, что можешь быстро вспомнить, где какие косяки. Но для показа, лучше будет хотя бы создать видимость, что с этим можно работать коллегиально.
это не значит, что ничего не просочилось. просто я посмотрел три класса и там везде было вот такое. при твоем вольном отношении к коду возможно, что где-то лежит
>//Кротов Сергей 4500 224331 перезвонить по телефону 3215411
надо разок так обосраться, чтобы потом поменять отношение. я когда первый аудит проходил, вообще не понимал нахуй он нужен - у меня же все нормально! оказалось, я похерил все, что можно было похерить.
Есть шаблон сайта, который юзает контора. CMS нужно указать, где находится папка core от корня.
Как мы делаем: закидываем файл с выводом результата команды <? __DIR__; ?> в public_html и потом дописываем до конца.
Короч, если ты не понял, что я несу, то сам вопрос таков:
Есть ли какая-то встроенная функция, чтобы от результата __DIR__ можно было отрезать часть пути с конца?
Изучи мануал по
basename
dirname
realpath
Также, можно использовать в пути .., который значит "подняться на папку вверх": http://phpfaq.ru/newbie/paths
Благодарствую.
ЧЯДНТ? Скиньте мне, пожалуйста, какую-нибудь тему, которая желала бы обновиться, чтобы я смог изучить этот вопрос.
Здесь обсуждается программирование, а не вордрес. Лучше зайди в /web и там спроси в вордпрес треде
Не, вопрос вполне нормальный. Он же спрашивает для того, чтобы протестировать сценарий обновления.
>>34247
Попробуй зайти на сайт темы и поискать раздел вроде releases. Может там есть старые версии.
Ну вот я например взял эту тему https://ru.wordpress.org/themes/belise-lite/ и нажал ссылку "Просмотреть в Trac" - https://themes.trac.wordpress.org/browser/belise-lite/ и тут есть папочки с разными версиями.
Они используют при разработке систему контроля версий (svn), гигантский репозиторий со всеми темами ( https://themes.svn.wordpress.org/belise-lite/ ). Наверно из нее как-то можно вытянуть старую версию, если разобраться. Вот тут что-то такое описывают: https://wordpress.stackexchange.com/questions/65056/how-to-get-themes-from-wordpress-com-per-svn
Также, тут описан другой способ: https://www.competethemes.com/blog/download-older-version-plugins-themes/
это норма. я так же делал. сейчас уже эти задачки кажутся простыми. просто делай дальше и больше.
Если ты чувствуешь, что не до конца разобрался в какой-то теме, можно попросить усложненную задачку, чтобы ты мог убедиться, что ты с ней справишься и не беспокоиться.
Имеется в виду как правильно распарсить вложенные скобки, преобразовать в простые логические условия, провалидировать в корректном ли порядке они идут и т.д.
И еще вопрос: есть же наверное какие-то библиотеки, которые этим занимаются? Или может бандлы для Симфони?
Из минусов - стремаюсь на свою карточку регать аккаунт после статьи https://geektimes.ru/post/247794/ , что скажете?
>>18558
Я увидел, что там используется KnpPagination, описание у него подозрительное, решил посмотреть его код и как чувствовал - нашел сомнительное место (использование $_GET):
- https://github.com/KnpLabs/knp-components/blob/master/src/Knp/Component/Pager/Paginator.php#L98
- https://github.com/KnpLabs/knp-components/blob/master/src/Knp/Component/Pager/Event/Subscriber/Sortable/ArraySubscriber.php#L48
- https://github.com/KnpLabs/knp-components/blob/master/src/Knp/Component/Pager/Event/Subscriber/Sortable/Doctrine/ORM/QuerySubscriber.php
Впрочем, они уже о проблеме знают: https://github.com/KnpLabs/knp-components/issues/160
А что там подозрительного? А подозрительно то, что они в ридми в примере кода указывают на возможность сортировки, но 1) нигде не передаются параметры сортировки и 2) белый список полей: https://github.com/KnpLabs/KnpPaginatorBundle
То, что параметр сортировки не передается из Request - значит, они сами откуда-то его берут (из $_GET в данном случае). Если не задан белый список полей - значит, что это может создать уязвимость, позволяющую злоумышленнику угадывать значеия скрытых полей в таблице.
Поясню. Допустим, у нас на сайте есть список пользователей с возможностью сортировки, и мы можем делать сортировку по любому полю. Допустим, мы хотим узнать email пользователя, который не выводится на сайте. Мы регистрируем аккаунты {QPaANUSexampleZckPUNCTUMcPNjom, n>CnANUSexaF[SmplePUNCTUMcCQhom, zl^3ANUSesZ$xamplePUNCTUMcrp!om и используя сортировку списка по email, определяем, в каком диапазоне (a-n или n-z) лежит первая буква списка. Затем сужаем диапазон и так примерно за сотню-две попыток получаем нужный email.
Разумеется, этот же принцип можно применить для подбора значения любого другого скрытого поля, включая хеш пароля, если нам известен механизм хеширования. Если он не известен, можно подбирать какой-нибудт токен или что-нибудь еще.
То есть сортировка без белого списка полей, если она там включена по умолчанию - это уязвимость.
Плюс, вот такой вот issue нашелся: https://github.com/KnpLabs/KnpPaginatorBundle/issues/386
-----
https://github.com/TheSidSpears/test_hub/blob/master/src/Controller/TestController.php#L38
Не стоит так экономить на строчках, получение $searchForm лучше сделать отдельной строкой.
https://github.com/TheSidSpears/test_hub/blob/master/src/Entity/Tag.php#L57
Вроде бы на такой случай есть аннотация iterable: http://php.net/manual/ru/language.types.iterable.php
Тестов что-то совсем не добавилось.
https://github.com/TheSidSpears/test_hub/blob/master/src/Entity/User.php#L74
Вот это гиблая идея, парсить на коленке имена. Бывают наверно имена более чем из 2 слов. Лучше сделать так: public function setName($firstName, $lastName). Или хранить данные как введены.
https://github.com/TheSidSpears/test_hub/blob/master/src/Entity/User.php#L84
> public function __toString()
Я бы советовал избегать __ToString. Он помогает скрыть информацию об ошибке, молча преобразуя объект в строку. В ситуациях вроде:
function doStmh(string $email) { }
doSmth($user)
или echo "Email = " . $user;
Если метода __toString нет, то оба примера выше выдадут ошибку.
https://github.com/TheSidSpears/test_hub/blob/master/src/Repository/TagRepository.php#L19
> SELECT t FROM ' . Tag::class . ' t');
Не удобнее ли писать 'SELECT t FROM Tag t' ?
https://github.com/TheSidSpears/test_hub/blob/master/templates/tags/list.html.twig#L28
> {% if tags.getTotalItemCount == 1 %}
> {% set tagWithSuffix = 'tag' %}
Может тебе посмотреть в расширения для локализации? Там должен быть синтаксис для форматирования строк с учетом особенностей языка. Например, в расширении Intl используется такой немного громоздкий синтаксис:
http://userguide.icu-project.org/formatparse/messages
>"{num_guests, plural, offset:1 "
> "=0 {{host} does not give a party.}"
> "=1 {{host} invites {guest} to her party.}"
> "=2 {{host} invites {guest} and one other person to her party.}"
> "other {{host} invites {guest} and # other people to her party.}}}"
903 килобайта JS в build/app.js - не слишком ли много?
>>18558
Я увидел, что там используется KnpPagination, описание у него подозрительное, решил посмотреть его код и как чувствовал - нашел сомнительное место (использование $_GET):
- https://github.com/KnpLabs/knp-components/blob/master/src/Knp/Component/Pager/Paginator.php#L98
- https://github.com/KnpLabs/knp-components/blob/master/src/Knp/Component/Pager/Event/Subscriber/Sortable/ArraySubscriber.php#L48
- https://github.com/KnpLabs/knp-components/blob/master/src/Knp/Component/Pager/Event/Subscriber/Sortable/Doctrine/ORM/QuerySubscriber.php
Впрочем, они уже о проблеме знают: https://github.com/KnpLabs/knp-components/issues/160
А что там подозрительного? А подозрительно то, что они в ридми в примере кода указывают на возможность сортировки, но 1) нигде не передаются параметры сортировки и 2) белый список полей: https://github.com/KnpLabs/KnpPaginatorBundle
То, что параметр сортировки не передается из Request - значит, они сами откуда-то его берут (из $_GET в данном случае). Если не задан белый список полей - значит, что это может создать уязвимость, позволяющую злоумышленнику угадывать значеия скрытых полей в таблице.
Поясню. Допустим, у нас на сайте есть список пользователей с возможностью сортировки, и мы можем делать сортировку по любому полю. Допустим, мы хотим узнать email пользователя, который не выводится на сайте. Мы регистрируем аккаунты {QPaANUSexampleZckPUNCTUMcPNjom, n>CnANUSexaF[SmplePUNCTUMcCQhom, zl^3ANUSesZ$xamplePUNCTUMcrp!om и используя сортировку списка по email, определяем, в каком диапазоне (a-n или n-z) лежит первая буква списка. Затем сужаем диапазон и так примерно за сотню-две попыток получаем нужный email.
Разумеется, этот же принцип можно применить для подбора значения любого другого скрытого поля, включая хеш пароля, если нам известен механизм хеширования. Если он не известен, можно подбирать какой-нибудт токен или что-нибудь еще.
То есть сортировка без белого списка полей, если она там включена по умолчанию - это уязвимость.
Плюс, вот такой вот issue нашелся: https://github.com/KnpLabs/KnpPaginatorBundle/issues/386
-----
https://github.com/TheSidSpears/test_hub/blob/master/src/Controller/TestController.php#L38
Не стоит так экономить на строчках, получение $searchForm лучше сделать отдельной строкой.
https://github.com/TheSidSpears/test_hub/blob/master/src/Entity/Tag.php#L57
Вроде бы на такой случай есть аннотация iterable: http://php.net/manual/ru/language.types.iterable.php
Тестов что-то совсем не добавилось.
https://github.com/TheSidSpears/test_hub/blob/master/src/Entity/User.php#L74
Вот это гиблая идея, парсить на коленке имена. Бывают наверно имена более чем из 2 слов. Лучше сделать так: public function setName($firstName, $lastName). Или хранить данные как введены.
https://github.com/TheSidSpears/test_hub/blob/master/src/Entity/User.php#L84
> public function __toString()
Я бы советовал избегать __ToString. Он помогает скрыть информацию об ошибке, молча преобразуя объект в строку. В ситуациях вроде:
function doStmh(string $email) { }
doSmth($user)
или echo "Email = " . $user;
Если метода __toString нет, то оба примера выше выдадут ошибку.
https://github.com/TheSidSpears/test_hub/blob/master/src/Repository/TagRepository.php#L19
> SELECT t FROM ' . Tag::class . ' t');
Не удобнее ли писать 'SELECT t FROM Tag t' ?
https://github.com/TheSidSpears/test_hub/blob/master/templates/tags/list.html.twig#L28
> {% if tags.getTotalItemCount == 1 %}
> {% set tagWithSuffix = 'tag' %}
Может тебе посмотреть в расширения для локализации? Там должен быть синтаксис для форматирования строк с учетом особенностей языка. Например, в расширении Intl используется такой немного громоздкий синтаксис:
http://userguide.icu-project.org/formatparse/messages
>"{num_guests, plural, offset:1 "
> "=0 {{host} does not give a party.}"
> "=1 {{host} invites {guest} to her party.}"
> "=2 {{host} invites {guest} and one other person to her party.}"
> "other {{host} invites {guest} and # other people to her party.}}}"
903 килобайта JS в build/app.js - не слишком ли много?
Нужно знание линукса и основных команд.
>>18828
Использовать тип позиционирования, для которого размер по умолчанию определяется содержимым. Например:
- display: inline-block без заданных размеров
- float: left
- position: absolute
- display: table
>>18958
Это зависит от того, как ты настроишь. В контейнере может быть много процессов.
> Или посоветуйте что-то для быстрого деплоя/развертывания одного проекта на N-нод
Деплой PHP кода или деплой нгинксов? Второе можно поручить админу, для первого использовать ansible.
>>19604
Ты не написал, какой командой ты пытаешься ее создавать, что пишет эта команда. По идее конечно должно работать и с аннотациями. Также, не забыл ли ты правильно указать use при использовании аннотаций? Он иведь тоже в неймспейсах находятся.
>>19631
PDO занимается только соединением с БД и отправкой в нее запросов. Надо дописать свой код, который будет брать полученные из формы данные и формировать на их основе SQL запрос.
>>19912
Нужен супервизор, который будет перезапускать скрипт при падении. Ловить исключение и перезапускать функцию - плохая идея, так как состояние программы может быть неправильным и будет накапливаться ошибки.
Нужно знание линукса и основных команд.
>>18828
Использовать тип позиционирования, для которого размер по умолчанию определяется содержимым. Например:
- display: inline-block без заданных размеров
- float: left
- position: absolute
- display: table
>>18958
Это зависит от того, как ты настроишь. В контейнере может быть много процессов.
> Или посоветуйте что-то для быстрого деплоя/развертывания одного проекта на N-нод
Деплой PHP кода или деплой нгинксов? Второе можно поручить админу, для первого использовать ansible.
>>19604
Ты не написал, какой командой ты пытаешься ее создавать, что пишет эта команда. По идее конечно должно работать и с аннотациями. Также, не забыл ли ты правильно указать use при использовании аннотаций? Он иведь тоже в неймспейсах находятся.
>>19631
PDO занимается только соединением с БД и отправкой в нее запросов. Надо дописать свой код, который будет брать полученные из формы данные и формировать на их основе SQL запрос.
>>19912
Нужен супервизор, который будет перезапускать скрипт при падении. Ловить исключение и перезапускать функцию - плохая идея, так как состояние программы может быть неправильным и будет накапливаться ошибки.
Я не очень разбираюсь в диаграммах, но мне кажется, у тебя ошибка. Ты используешь ER диаграмму в нотации crow's foot (кроме нее есть еще другие способы обозначать отношения: https://en.wikipedia.org/wiki/Entity–relationship_model#Cardinalities ). На ней мы отображаем сущности и связи между ними. bridge - это не сущность, это промежуточная таблица, которая нужна для реализации связи многие-ко-многим в SQL.
На всякий случай, вот тут есть хорошее объяснение, что значат разные пометки: http://www2.cs.uregina.ca/~bernatja/crowsfoot.html
У тебя пометка около tag не соответствует перечисленным.
Соответственно, на диаграмме должно быть 2 сущности, Пост и Тег и связь (Пост) "отмечен" (Тегами).
Какие свойства этой связи?
- Пост может быть отмечен 0, 1 или многими Тегами
- у Тега может быть 1 или более постов. Тега без постов не существует.
>>19939
>>19947
>>19954
Объяснение тут: http://www2.cs.uregina.ca/~bernatja/crowsfoot.html
Две палочки значат "от 1 до 1". Одна палочка может быть в сочетании с кругом (снаружи) - от 0 до 1 или с лапкой (внутри) - от 1 и более.
Можно было бы в setRank() поставить защиту от установки неправильного ранга с выбрасыванием исключения (если ранг < 1 или > 3).
Давай, ради расширения кругозора, ты попробуешь сделать максимально параноидальный код, который проверяет все параметры на разумность. Ну например, чтобы нельзя было попытаться выставить отрицательную зарплату или удалить работника, который не работает в этом департаменте.
Это поможет тебе увидеть, как ООП и инкапсуляция (закрытие доступа к полям извне) позволяют сделать защищенный от ошибок код, который в любой ситуации работает корректно, даже при попытке подать на вход некорреткные данные.
Говоря о корретности программы, есть еще один интересный подход - Value Objects. Суть его в том, что мы могли бы для отдельных значений в нашей программе вроде ранга создать классы - класс Rank, который оборачивает число (то есть это класс с единственным неизменяемым приватным полем rank, которое задается в конструкторе. Он должен быть неизменным после создания). В чем плюс?
- мы можем гарантировать корректность значения. Например, прямо в конструкторе Rank поставить проверку, что он должен быть от 1 до 3 и не позволять создавать некорректный ранг. В этом случае, если у нас есть объект Rank, то это значит, что ранг в нем 100% корректный.
- мы можем задать допустимый набор действий с значением с помощью методов. Ну например, мы можем не выдавать ранг как число наружу, а сделать только методы вроде $rank->isEqual(1) и $rank->increase(2) и тем самым запретить перемножать ранги (с обычным числом по ошибке это можно сделать). При изменении ранга через методы мы можем предоставратить получение неправильных значений (повысить 3-й ранг до 4-го)
- мы можем ставить тайп-хинты и писать например setRank(Rank $rank) и это не позволит передать в функцию что-то, кроме ранга (зарплату например). В случае int $rank такой защиты нет. Также такие тайп-хинты делают код еще понятнее.
- мы можем защищаться от ошибок, связанных с единицами измерения. Если у нас время выражено числом, то в чем оно измеряется? В часах, минутах, секундах, миллисекундах? Если длина, то в метрах или футах? Если момент времени, то в каком часовом поясе? В случае с ValueObject единица измерения известна и мы можем сделать методы $time->getAsSeconds(), $time->getAsHours(), защищая себя от ошибок при ручной конвертации.
- мы можем делать полезные вспомогательные методы, например, для времени мы можем сделать метод $time->diff($otherTime), вычисляющий разницу между 2 точками во времени.
В чем минус?
- сильно раздувается объем кода
Иммутабельность нужна, чтобы защититься от ошибок, когда мы меняем использующийся в нескольких местах объект.
Может, ты захочешь тут применить этот паттерн. Он обычно применяется для простых знаечний вроде Денег, Времени, Точек (координат), Цветов. В PHP есть классы DateTimeImmutable и DateImmutable.
- http://design-pattern.ru/patterns/value-object.html
- https://martinfowler.com/bliki/ValueObject.html (сложно)
> public function getWorker(int $key): AbstractWorker
> public function deleteWorker(int $key): void
Это не очень удачные методы, так как непонятно, где брать этот key. У работника ведь нет метода getKey(). Но он и не нужен - работник сам по себе имеет идентичность и можно просто передавать объект в deleteWorker.
> public function selectWorkers(string $profession): array
Не хочешь подумать над универсальной функцией поиска по произвольным критериям?
> $workersOfCertainProfession = array();
Можно просто $result.
> public function changeBoss(int $oldBoss, int $newBoss)
Та же проблема. Передаются какие-то непонятные инты, которые непонятно где брать.
> class HiringWorkers
Этот класс мог бы хранить в себе (или принимать через конструктор) базовые значения зарплат, чтобы не дублировать их многократно.
> $department->selectWorkers("Engineer");
Лучше Engineer::class
> for ($i = 0; $i < count($workersOfCertainProfession) - 2; $i++){
> if ($workersOfCertainProfession[$i]->getRank() > $workersOfCertainProfession[$i+1]->getRank()){
> $buf = $workersOfCertainProfession[$i];
> $workersOfCertainProfession[$i] = $workersOfCertainProfession[$i+1];
Сортировка пузырьком??? Во-первых, ее надо выносить в отдельный метод (чтобы не ухудшать читабельность кода и не раздувать функцию), во-вторых, используй usort с анонимной функцией.
> ceil(count($workersOfCertainProfession) / 2.5));
В задании было написано 40%, а ты заменил его на 2.5, в итоге я секунд 10 думал, откуда тут эта цифра. Лучше было умножать на 0.4 или на $engineerCutPercent.
Цикл удаления переусложнен из-за того, что твой код требует определить key работника, а это просто не сделать. Код мог бы быть проще и короче.
> changeDataAnalytics
Тут отбор аналитиков можно было сделать функцией. Также, функцию смены босса можно было спроектирвоать более удачно и код был бы проще и аккуратнее. Попробуй написать прототип (заголовок) функции замены босса, не думая о том, как устроен Департамент внутри и как там хранятся работники. Как бы ты ее записал?
> $worker->setRank($worker->getRank()+1);
Возможно, есть смысл сделать метод повышения работника.
В общем, для упрощения антикризисного кода я бы советовал улучшить:
- функцию поиска работников
- функцию увольнения
- функцию замены босса
- переделать сортировку
Можно было бы в setRank() поставить защиту от установки неправильного ранга с выбрасыванием исключения (если ранг < 1 или > 3).
Давай, ради расширения кругозора, ты попробуешь сделать максимально параноидальный код, который проверяет все параметры на разумность. Ну например, чтобы нельзя было попытаться выставить отрицательную зарплату или удалить работника, который не работает в этом департаменте.
Это поможет тебе увидеть, как ООП и инкапсуляция (закрытие доступа к полям извне) позволяют сделать защищенный от ошибок код, который в любой ситуации работает корректно, даже при попытке подать на вход некорреткные данные.
Говоря о корретности программы, есть еще один интересный подход - Value Objects. Суть его в том, что мы могли бы для отдельных значений в нашей программе вроде ранга создать классы - класс Rank, который оборачивает число (то есть это класс с единственным неизменяемым приватным полем rank, которое задается в конструкторе. Он должен быть неизменным после создания). В чем плюс?
- мы можем гарантировать корректность значения. Например, прямо в конструкторе Rank поставить проверку, что он должен быть от 1 до 3 и не позволять создавать некорректный ранг. В этом случае, если у нас есть объект Rank, то это значит, что ранг в нем 100% корректный.
- мы можем задать допустимый набор действий с значением с помощью методов. Ну например, мы можем не выдавать ранг как число наружу, а сделать только методы вроде $rank->isEqual(1) и $rank->increase(2) и тем самым запретить перемножать ранги (с обычным числом по ошибке это можно сделать). При изменении ранга через методы мы можем предоставратить получение неправильных значений (повысить 3-й ранг до 4-го)
- мы можем ставить тайп-хинты и писать например setRank(Rank $rank) и это не позволит передать в функцию что-то, кроме ранга (зарплату например). В случае int $rank такой защиты нет. Также такие тайп-хинты делают код еще понятнее.
- мы можем защищаться от ошибок, связанных с единицами измерения. Если у нас время выражено числом, то в чем оно измеряется? В часах, минутах, секундах, миллисекундах? Если длина, то в метрах или футах? Если момент времени, то в каком часовом поясе? В случае с ValueObject единица измерения известна и мы можем сделать методы $time->getAsSeconds(), $time->getAsHours(), защищая себя от ошибок при ручной конвертации.
- мы можем делать полезные вспомогательные методы, например, для времени мы можем сделать метод $time->diff($otherTime), вычисляющий разницу между 2 точками во времени.
В чем минус?
- сильно раздувается объем кода
Иммутабельность нужна, чтобы защититься от ошибок, когда мы меняем использующийся в нескольких местах объект.
Может, ты захочешь тут применить этот паттерн. Он обычно применяется для простых знаечний вроде Денег, Времени, Точек (координат), Цветов. В PHP есть классы DateTimeImmutable и DateImmutable.
- http://design-pattern.ru/patterns/value-object.html
- https://martinfowler.com/bliki/ValueObject.html (сложно)
> public function getWorker(int $key): AbstractWorker
> public function deleteWorker(int $key): void
Это не очень удачные методы, так как непонятно, где брать этот key. У работника ведь нет метода getKey(). Но он и не нужен - работник сам по себе имеет идентичность и можно просто передавать объект в deleteWorker.
> public function selectWorkers(string $profession): array
Не хочешь подумать над универсальной функцией поиска по произвольным критериям?
> $workersOfCertainProfession = array();
Можно просто $result.
> public function changeBoss(int $oldBoss, int $newBoss)
Та же проблема. Передаются какие-то непонятные инты, которые непонятно где брать.
> class HiringWorkers
Этот класс мог бы хранить в себе (или принимать через конструктор) базовые значения зарплат, чтобы не дублировать их многократно.
> $department->selectWorkers("Engineer");
Лучше Engineer::class
> for ($i = 0; $i < count($workersOfCertainProfession) - 2; $i++){
> if ($workersOfCertainProfession[$i]->getRank() > $workersOfCertainProfession[$i+1]->getRank()){
> $buf = $workersOfCertainProfession[$i];
> $workersOfCertainProfession[$i] = $workersOfCertainProfession[$i+1];
Сортировка пузырьком??? Во-первых, ее надо выносить в отдельный метод (чтобы не ухудшать читабельность кода и не раздувать функцию), во-вторых, используй usort с анонимной функцией.
> ceil(count($workersOfCertainProfession) / 2.5));
В задании было написано 40%, а ты заменил его на 2.5, в итоге я секунд 10 думал, откуда тут эта цифра. Лучше было умножать на 0.4 или на $engineerCutPercent.
Цикл удаления переусложнен из-за того, что твой код требует определить key работника, а это просто не сделать. Код мог бы быть проще и короче.
> changeDataAnalytics
Тут отбор аналитиков можно было сделать функцией. Также, функцию смены босса можно было спроектирвоать более удачно и код был бы проще и аккуратнее. Попробуй написать прототип (заголовок) функции замены босса, не думая о том, как устроен Департамент внутри и как там хранятся работники. Как бы ты ее записал?
> $worker->setRank($worker->getRank()+1);
Возможно, есть смысл сделать метод повышения работника.
В общем, для упрощения антикризисного кода я бы советовал улучшить:
- функцию поиска работников
- функцию увольнения
- функцию замены босса
- переделать сортировку
Тайп хинты есть с 5 версии, в 7 значительно улучшены: http://php.net/manual/ru/functions.arguments.php#functions.arguments.type-declaration
>>20286
Давай по частям.
> свойства, которое хранится как массив, а в БД как json.
Это надо делать не в форме, это надо делать в Доктрине. В ней создаешь свой кастомный тип данных, ставишь его полю и пишешь, как преобразовывать значения поля при загрузке/записи в БД. Может даже такой тип уже написан кем-то.
Но конечно я бы тут применил ООП и сделал массив объектов Property. В этом случае может быть это даже работало бы с CollectionType без преобразований.
Что касается форм, то да, Data Transformer тут бы подошел. Либо можно написать свой FormType для работы с таким типом данных.
>>20332
Есть в мануале https://dev.mysql.com/doc/refman/5.5/en/optimizing-innodb-bulk-data-loading.html
>>20355
Вообще не, внутри [] круглые скобки не имеют специального значения.
>>20471
Это наверно не совсем то, что ты хотел, но:
1) http://php.net/manual/ru/language.basic-syntax.phpmode.php
2) https://github.com/codedokode/pasta/blob/master/php/templates.md
Тайп хинты есть с 5 версии, в 7 значительно улучшены: http://php.net/manual/ru/functions.arguments.php#functions.arguments.type-declaration
>>20286
Давай по частям.
> свойства, которое хранится как массив, а в БД как json.
Это надо делать не в форме, это надо делать в Доктрине. В ней создаешь свой кастомный тип данных, ставишь его полю и пишешь, как преобразовывать значения поля при загрузке/записи в БД. Может даже такой тип уже написан кем-то.
Но конечно я бы тут применил ООП и сделал массив объектов Property. В этом случае может быть это даже работало бы с CollectionType без преобразований.
Что касается форм, то да, Data Transformer тут бы подошел. Либо можно написать свой FormType для работы с таким типом данных.
>>20332
Есть в мануале https://dev.mysql.com/doc/refman/5.5/en/optimizing-innodb-bulk-data-loading.html
>>20355
Вообще не, внутри [] круглые скобки не имеют специального значения.
>>20471
Это наверно не совсем то, что ты хотел, но:
1) http://php.net/manual/ru/language.basic-syntax.phpmode.php
2) https://github.com/codedokode/pasta/blob/master/php/templates.md
Не знаю, в чем проблема. А что, если открыть страницу в браузере, потом открыть ее исходный HTML код (меню или Ctrl + U) и сравнить с первоначальным HTML?
Также, доктайп бы не помешал.
>>22056
есть, погугли drag and drop file upload
>>22230
https://repl.it/repls/NippyGraciousCrayfish
Подсказка: getNormalHours проще посчитать как общее число часов минус переработка.
А так, решено верно.
>>22272
ВЫзовом внешней программы-проигрывателя.
>>22460
Можно попробовать выставить какие-то агрессивные параметры кеширования для страницы и ресурсов к ней - тогда браузер сможет открыть ее из кеша, если она там будет лежать. Но это не гарантированно.
> Я тебя правильно понял? https://github.com/TheSidSpears/test_hub/commit/48de6c290d05ca63a48a5aa7bf8fbf67fb67fb5f
Да.
> В этом файле стандартные переменные APP_ENV и DATABASE_URL. Зачем их переименовывать и как их система прочтет? (в этом разобраться самому)
ну я предлагал добавить префиксы, чтобы было видно, от какого приложения эти переменные и чтобы они не конфликтоваи с другими. Может, и не стоит заморачиваться конечно.
> Нужно тестировать репозитории на копии основной БД? А как держать эту БД актуальной? Это ж нужно миграции и там и там проводить. Как-то не удобным это кажется
В идеале - тестовая БД, которая заполняется перед тестами. Миграции руками проводить не надо, надо все автоматизировать.
Да, это сложновато, ну а как без этого тестировать код, завязанный на БД? Не делать же полноценную эмуляцию всей SQL-базы данных. Ну и без этого тебе ведь руками все тестировать придется.
Это ты еще до браузерного тестирования и селениума не дошел, там еще сложнее.
> Нет, эти 2 ф-ии используются исключительно для заполнения Fixtures
Тогда ок.
> Я попытался разобраться https://drive.google.com/file/d/1Gvt38WwASpFcdFU3z9ZDuvrZ3pfaWbun/view?usp=sharing
> Видимо, не подойдёт
А ты попробуй код написать ;)
Например, $repo->findBy(['tag' => $tags]) или findByTag($tags) и посмогтреть что он найдет и какой SQL запрос сформирует.
> В нём определяется какой-то persister
Судя по названию, это объект для сохранения (persist) сущностей в БД.
> Видим, что класс зависит от `InheritanceType`. Названия классов намекают, будет ли проходить поиск по конкретной таблице или по объединенной (joined)
Да, это для разных вариантов наследования таблиц вроде http://design-pattern.ru/patterns/class-table-inheritance.html .
>> Вот это мне не нравится. У тебя переменная может быть передана, а может не быть. Как писать надежный код в такой ситуации?
> А как быть то? Передавать isMainRoute во всех контроллерах избыточно, а как-то определять, что "вид вызван из MainController" надо
Тут надо подумать логически. Вот у нас есть серединка страницы, которая разная и формируется контроллерам, а есть шапка/меню/подвал/сайдбар (лейуат), которые везде одинаковые. Но им тоже нужны данные. Надо искать варианты, например:
- сделать отдельный "контроллер" (или контроллеры) для сбора данных для лейаута. Или оформить их как "виджеты".
- добавить свои переменные в {{ app }}
- добавить глобальные переменные в твиг
- сделать, чтобы эти части вызывали какие-то функции или методы и получали нужные им данные
- внедриться в событие, которое срабатывает до запуска контроллера и куда-нибудь что-нибудь передает
- сделать наследование контроллера и формировать данные для шапки в базовом контроллере
То есть поискать варианты, лучшие практики.
Вот например:
- https://symfony.com/doc/current/templating/global_variables.html
- https://stackoverflow.com/questions/21094888/symfony2-how-to-retrieve-data-from-database-globally-in-every-page
> использовать синтаксис для переводимых строк? Это как?
Смотри например класс MessageFormatter в расширении Intl, смотри средства локализации в Симфони:
http://userguide.icu-project.org/formatparse/messages
>"{num_guests, plural, offset:1 "
> "=0 {{host} does not give a party.}"
> "=1 {{host} invites {guest} to her party.}"
> "=2 {{host} invites {guest} and one other person to her party.}"
> "other {{host} invites {guest} and # other people to her party.}}}"
>> Почему пагинатор передается в аргументы метода контроллера? Это такой DI?
> Как я понял, нужно в конструкторе его определять?
Не, наверно надо оставить DI. Тут нет проблемы, я ошибся.
>> А зачем else?
> При переходе на следующую страницу, условие $form->isSubmitted() уже не выполняется, поэтому я беру $searchString из get-параметра
Это какой-то косяк в твоем использовании формы. Если форма GET, то она дложна брать данные из GET.
> Я тебя правильно понял? https://github.com/TheSidSpears/test_hub/commit/48de6c290d05ca63a48a5aa7bf8fbf67fb67fb5f
Да.
> В этом файле стандартные переменные APP_ENV и DATABASE_URL. Зачем их переименовывать и как их система прочтет? (в этом разобраться самому)
ну я предлагал добавить префиксы, чтобы было видно, от какого приложения эти переменные и чтобы они не конфликтоваи с другими. Может, и не стоит заморачиваться конечно.
> Нужно тестировать репозитории на копии основной БД? А как держать эту БД актуальной? Это ж нужно миграции и там и там проводить. Как-то не удобным это кажется
В идеале - тестовая БД, которая заполняется перед тестами. Миграции руками проводить не надо, надо все автоматизировать.
Да, это сложновато, ну а как без этого тестировать код, завязанный на БД? Не делать же полноценную эмуляцию всей SQL-базы данных. Ну и без этого тебе ведь руками все тестировать придется.
Это ты еще до браузерного тестирования и селениума не дошел, там еще сложнее.
> Нет, эти 2 ф-ии используются исключительно для заполнения Fixtures
Тогда ок.
> Я попытался разобраться https://drive.google.com/file/d/1Gvt38WwASpFcdFU3z9ZDuvrZ3pfaWbun/view?usp=sharing
> Видимо, не подойдёт
А ты попробуй код написать ;)
Например, $repo->findBy(['tag' => $tags]) или findByTag($tags) и посмогтреть что он найдет и какой SQL запрос сформирует.
> В нём определяется какой-то persister
Судя по названию, это объект для сохранения (persist) сущностей в БД.
> Видим, что класс зависит от `InheritanceType`. Названия классов намекают, будет ли проходить поиск по конкретной таблице или по объединенной (joined)
Да, это для разных вариантов наследования таблиц вроде http://design-pattern.ru/patterns/class-table-inheritance.html .
>> Вот это мне не нравится. У тебя переменная может быть передана, а может не быть. Как писать надежный код в такой ситуации?
> А как быть то? Передавать isMainRoute во всех контроллерах избыточно, а как-то определять, что "вид вызван из MainController" надо
Тут надо подумать логически. Вот у нас есть серединка страницы, которая разная и формируется контроллерам, а есть шапка/меню/подвал/сайдбар (лейуат), которые везде одинаковые. Но им тоже нужны данные. Надо искать варианты, например:
- сделать отдельный "контроллер" (или контроллеры) для сбора данных для лейаута. Или оформить их как "виджеты".
- добавить свои переменные в {{ app }}
- добавить глобальные переменные в твиг
- сделать, чтобы эти части вызывали какие-то функции или методы и получали нужные им данные
- внедриться в событие, которое срабатывает до запуска контроллера и куда-нибудь что-нибудь передает
- сделать наследование контроллера и формировать данные для шапки в базовом контроллере
То есть поискать варианты, лучшие практики.
Вот например:
- https://symfony.com/doc/current/templating/global_variables.html
- https://stackoverflow.com/questions/21094888/symfony2-how-to-retrieve-data-from-database-globally-in-every-page
> использовать синтаксис для переводимых строк? Это как?
Смотри например класс MessageFormatter в расширении Intl, смотри средства локализации в Симфони:
http://userguide.icu-project.org/formatparse/messages
>"{num_guests, plural, offset:1 "
> "=0 {{host} does not give a party.}"
> "=1 {{host} invites {guest} to her party.}"
> "=2 {{host} invites {guest} and one other person to her party.}"
> "other {{host} invites {guest} and # other people to her party.}}}"
>> Почему пагинатор передается в аргументы метода контроллера? Это такой DI?
> Как я понял, нужно в конструкторе его определять?
Не, наверно надо оставить DI. Тут нет проблемы, я ошибся.
>> А зачем else?
> При переходе на следующую страницу, условие $form->isSubmitted() уже не выполняется, поэтому я беру $searchString из get-параметра
Это какой-то косяк в твоем использовании формы. Если форма GET, то она дложна брать данные из GET.
Смотри что есть тут https://developer.microsoft.com/en-us/microsoft-edge/tools/
Либо виртуалка с виндой (майкрософт дает лицензионные), либо сайты-скриншотеры.
>>23925
Можно просто циклом foreach пройти по массиву и по очереди каждый элемент поменять. Если не пытаться проверить все телефоны за 1 заход, то будет проще.
>>24213
Могу дать в помощью статью про ИЕ: https://github.com/codedokode/pasta/blob/master/html/markup-for-ie.md
>>24496
есть варианты
- inline-block
- float: left
- display: table-cell/table-row/table
- flexbox
>>24948
Про наследование написано немного тут
- http://design-pattern.ru/patterns/single-table-inheritance.html
- http://design-pattern.ru/patterns/class-table-inheritance.html
- http://design-pattern.ru/patterns/concrete-table-inheritance.html
>>Ключом в event_type наверно лучше сделать id. Он меньше места занимает.
> А если в таблице появится поле owner_user_id, то ключом можно сделать сочетание type и owner_user_id? Или id будет удобнее?
Можно использовать любой вариант.
> Если периодичность перенести в таблицу Events, то это поле будет или дублироваться или придется каждый раз указывать периодичность. Насколько приемлемо дублирование, нужно выбрать то, которое будет приоритетное?
Наверно, тогда лучше назвать поле в Event_type is_annual_by_default, и использовать его только для начального значения в галочке. Дублирования не будет.
>>34979
AWS недешевый. Подозреваю, что если и есть бесплатный тариф, он с какими-то подвохами. Не вариант завести виртуальную карточку от того же qiwi или яндекс-денег? Они правда могут ее не принять, DO например не принимает.
Для дешевых VPS есть poiskvps.ru, но там в основном сервисы с русскими или СНГ-шными корнями.
Также, открою секрет за 1 евро в мес. можно у арубы арендовать.
Смотри что есть тут https://developer.microsoft.com/en-us/microsoft-edge/tools/
Либо виртуалка с виндой (майкрософт дает лицензионные), либо сайты-скриншотеры.
>>23925
Можно просто циклом foreach пройти по массиву и по очереди каждый элемент поменять. Если не пытаться проверить все телефоны за 1 заход, то будет проще.
>>24213
Могу дать в помощью статью про ИЕ: https://github.com/codedokode/pasta/blob/master/html/markup-for-ie.md
>>24496
есть варианты
- inline-block
- float: left
- display: table-cell/table-row/table
- flexbox
>>24948
Про наследование написано немного тут
- http://design-pattern.ru/patterns/single-table-inheritance.html
- http://design-pattern.ru/patterns/class-table-inheritance.html
- http://design-pattern.ru/patterns/concrete-table-inheritance.html
>>Ключом в event_type наверно лучше сделать id. Он меньше места занимает.
> А если в таблице появится поле owner_user_id, то ключом можно сделать сочетание type и owner_user_id? Или id будет удобнее?
Можно использовать любой вариант.
> Если периодичность перенести в таблицу Events, то это поле будет или дублироваться или придется каждый раз указывать периодичность. Насколько приемлемо дублирование, нужно выбрать то, которое будет приоритетное?
Наверно, тогда лучше назвать поле в Event_type is_annual_by_default, и использовать его только для начального значения в галочке. Дублирования не будет.
>>34979
AWS недешевый. Подозреваю, что если и есть бесплатный тариф, он с какими-то подвохами. Не вариант завести виртуальную карточку от того же qiwi или яндекс-денег? Они правда могут ее не принять, DO например не принимает.
Для дешевых VPS есть poiskvps.ru, но там в основном сервисы с русскими или СНГ-шными корнями.
Также, открою секрет за 1 евро в мес. можно у арубы арендовать.
Если я кому-то не ответил, напомните, пожалуйста, о себе в новом треде.
> Ошибку выдает такую: String could not be parsed as XML. Как и что тогда передавать итератору?
Ты уверен, что ошибка на строке с итератором, а не на строке simplexml_load_file? Скорее всего там просто некорретный XML, можно проверить его валидатором XML, например, тут: https://www.xmlvalidation.com/ или в любом другом.
>>30614
Ок, спасибо за помощь.
>>30625
MVC - это архитектура, у меня есть про нее урок: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>31257
У каждого треда можно определить время последнего поста в нем (lastBumpDate). Если отсортировать треды по убыванию этого времени, то получится как раз то, что нужно.
А дальше уже идут нюансы. Например, бамп лимит - если в треде более 500 постов, то при расчете lastBumpDate берется время 500-го поста, а не последнего. Закрепленные треды - идут всегда раньше, чем незакрепленные.
Ты знаком с SQL? Это там не так сложно сделать.
Архивирование делается примерно так: раз в час, минуту, сутки или как-то еще запускаем скрипт, который сортирует треды и находит те, что находятся ниже определенной позиции. Они архивируются. Это может быть как просто добавление пометки в таблицу, так и перемещение в отдельную таблицу (чтобы основная таблица оставалась маленькой и быстрее работала).
Вот еще, не знаю, поможет ли, урок про нормализацию БД: https://github.com/codedokode/pasta/blob/master/db/normalization.md
При проектировании лучше всего сначала спроектирвоать БД в нормализованном виде. Позже для оптимизации допустимо применить денормализацию, то есть дублирование данных.
> что значит поле bump
Где ты увидел это поле? В каком-то уроке или в каком-то движке?
> Ошибку выдает такую: String could not be parsed as XML. Как и что тогда передавать итератору?
Ты уверен, что ошибка на строке с итератором, а не на строке simplexml_load_file? Скорее всего там просто некорретный XML, можно проверить его валидатором XML, например, тут: https://www.xmlvalidation.com/ или в любом другом.
>>30614
Ок, спасибо за помощь.
>>30625
MVC - это архитектура, у меня есть про нее урок: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>31257
У каждого треда можно определить время последнего поста в нем (lastBumpDate). Если отсортировать треды по убыванию этого времени, то получится как раз то, что нужно.
А дальше уже идут нюансы. Например, бамп лимит - если в треде более 500 постов, то при расчете lastBumpDate берется время 500-го поста, а не последнего. Закрепленные треды - идут всегда раньше, чем незакрепленные.
Ты знаком с SQL? Это там не так сложно сделать.
Архивирование делается примерно так: раз в час, минуту, сутки или как-то еще запускаем скрипт, который сортирует треды и находит те, что находятся ниже определенной позиции. Они архивируются. Это может быть как просто добавление пометки в таблицу, так и перемещение в отдельную таблицу (чтобы основная таблица оставалась маленькой и быстрее работала).
Вот еще, не знаю, поможет ли, урок про нормализацию БД: https://github.com/codedokode/pasta/blob/master/db/normalization.md
При проектировании лучше всего сначала спроектирвоать БД в нормализованном виде. Позже для оптимизации допустимо применить денормализацию, то есть дублирование данных.
> что значит поле bump
Где ты увидел это поле? В каком-то уроке или в каком-то движке?
Это копия, сохраненная 6 марта 2018 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.