Вы видите копию треда, сохраненную 13 августа 2015 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Почему PHP? Потому что фейсбук и википедия на нем написаны, и вакансий море, и учить легко.
Это тред для начинающих. Не написал за свою жизнь ни одной программы? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Netbeans PHP или PhpStorm (с ним будет удобнее).
Предыдущий тред был тут: >>503607
Что самое главное для программиста? Умение аккуратно оформлять код (читай второй пост).
Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП отвечает даже на самые нубские вопросы. ОП заходит где-то раз в день-два, не жди его, решай задачки дальше.
У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Учебник дает основы языка PHP, но чтобы делать сайты, этого недостаточно. Если ты его прошел, то надо переходить в более серьезным задачкам, которые научат тебя как выдавать страницы в браузер, работе с таблицами в БД, работе с формами, MVC.
- Простая, но полезная задача сделать список студентов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Yii2: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование
- Если ты все решил, переходи к Symfony 2/Doctrine 2
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://gist.github.com/codedokode/10774100
https://gist.github.com/codedokode/7054af4a03865c4cc863
Может тебе понадобится пользоваться командной строкой, вот гайд https://gist.github.com/codedokode/10539568
Вот небольшой туториал по тому как начать использовать PHP на сервере для отдачи странички в браузер: https://php.net/manual/ru/tutorial.php Увы, уроков плавно подводящих к тому, как сделать задачи выше, пока нет, так что если что, задавай вопросы.
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://gist.github.com/codedokode/58ebc90bd006baf4b35c
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://gist.github.com/codedokode/10539213
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.github.io/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git:
Подскажи сайты для поиска работы, я не умею гуглить? brainstorage.me, geekjob.ru, hh.ru
Нужен ли ООП, фреймворки, MVC? — Да, однозначно. Посмотри любую вакансию.
Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.net/45000175
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
Где искать работу и заказы — hh.ru, geekjob.ru, brainstorage.me, fl.ru, odesk.com. Имей в виду, что кроме фриланса есть еще постоянная удаленная работа (remote job) когда тебе не надо тратить время на поиск заказов и переговоры с неадекватными заказчиками.
Если тебе лень выравнивать код руками, закачай его на 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/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
Если тебе лень выравнивать код руками, закачай его на 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/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
>>507754 Анон, зацени файлообменник: http://rocketfiles.zz.mu/
>>507767 https://github.com/V3N0m21/Uppu3
>>508294 https://github.com/blackberryJam/abiturients
>>508913 https://github.com/Si0n/register3
Другие аноны:
>>506998
Ответ неправильынй получается, должно быть 61270 во втором банке.
Также, нельзя выходить изцикла если сумма < 5000 так как на нее могут начислиться проценты и получится больше 5000, а ты это не учел.
Роскошный дизайн все-таки у этого чувака с рокетфайлз.
Интересно бы знать, где подсмотрел макет, и как называется такой стиль.
Схоронил себе названия шрифтов (BravoRegular для заголовков, ArianAMUSerifRegular для контента).
Давеча прочитал книгу Robin Williams (как ни странно, это она, а не он) "Дизайн для недизайнеров". Несмотря на дурацкое название, книга оказалась ну очень хорошей. Объясняются именно принципы хорошего дизайна, такие как контрастность, группировка смысловых элементов, выравнивание по базовым линиям, повторение элементов, резервирование большого кол-ва пустого пространства, благодаря чему страница выглядит неперегруженной и легкой.
Вот в этой работе все есть. Все элементы выровнены, шрифты грамотно подобраны, хорошая контрастность и акцент внимания посетителя на важных объектах, большое количество свободного места.
Для сравнения можно посмотреть работы быдлокодеров http://rutracker.org/forum/viewtopic.php?t=2891516 Так верстать нельзя.
Все как один уныло копируют стандартные темы вордпресса с небольшими вариациями, иногда с жалкой претензией на оригинальность, вроде аляповатых вензелей, или большого количества картинок на заднем плане, которые утомляют и перегружают интерфейс.
Кстати, вопрос по шрифтам. Можно ли сейчас использовать ну любой шрифт, какой я найду в интернете? Раньше шрифт обязан был быть на машине пользователя, но сейчас как бы 21 век, и можно выбросить на помойку ариал с таймсом, все красивые шрифты вроде бы можно подгрузить джаваскриптом с каких-нибудь облачных хранилищ гугла или яндекса, как я слышал.
Какие есть недостатки у такого подхода?
>>510051
Ты мне за неймспейсы не до конца пояснил. >>509823
Нет, даже не внешние хранилища. Шрифт можно сохранить у себя на сервере http://rocketfiles.zz.mu/app/templates/default/css/fonts.css
Но с этим наверняка связана куча подводных камней, интересная тема.
http://htmlbook.ru/css/font-face
>Браузер Internet Explorer до версии 9.0 поддерживает только шрифты формата EOT (не нужны)
>Opera в некоторых случаях может не показывать на веб-странице текст выбранным шрифтом, заменяя его стандартным. Причём для локальных документов всё работает корректно. Это происходит в тех случаях, когда имя пользователя в Windows написано кириллицей.
http://caniuse.com/#search=font-face
Опера-мини подкачала.
Еще сюрпризы?
Приятно конечно читать такие отзывы :3 Дизайн я честно спиздил отсюда: http://www.xfilesharingtemplates.com/classic-xfilesharing-pro-theme.html
Изначально хотел другой шаблон у них спиздить, там где космос и ракета с космонавтами на фоне, долго сидел в фотошопе и гугле, пытаясь что-то родить более-менее стоящее, но в итоге плюнул на это дело, т.к. годных картинок близких по стилю друг к другу я не нашел. А сам рисовать не умею. В итоге пришлось другой выбрать, попроще.
Кстати, у них сайт какой-то ебанутый. Когда заходишь туда, то через некоторое время тебе какой-то долбоеб начинает писать навязчиво, мол хули ты тут лазиешь? Один даже грозился меня по ай пи забанить, лол.
Любые шрифты через font-face подключаются. Если где-то в старых версиях IE или еще где-то не поддерживается, то и хрен с ними. Шрифты то эти для красивостей, функционал сайта никак не пострадает.
Да, у него есть способности к хорошему оформлению, к подбору гармонирующих шрифтов/цветов, но там есть и небольшие косяки, например некоторые иконки бессмысленные (и лучше были использовать просто абстрактный маркер), да и для файлообменника мне дизайн кажется перегруженным (например блоки с булшит-текстом имхо лишние), мне больше нравится такой стиль: http://ya.ru/, это конечно мое имхо, но я бы выпилил галочку, булшит-тексты, плашку под формой, уменьшил логотип раза в 2, ужал футер, шапку бы сделал чуть менее тяжелой.
Некоторые надписи плоховато читаются из-за слишком узких и мелких букв, некоторые места (форма логина вверху) слишком слабоконтрастны.
На большой ширине экрана (можно увидеть, уменьшив масштаб) табы на форме разваливаются — значит, они сверстаны неправильно.
В анимации переключения табов тоже есть косяк — некоторые элементы (кнопка загрузить например, чекбокс) просто мигают, но остаются на своих местах. Зачем тогда их анимировать? Это только отвлекает внимание, они не должны мигать.
В поле для ссылки забыт паддинг слева/справа.
Красная буква N в футере наверно лучше бы смотрелась если была чуть посветлее, так как она на темном фоне.
На большой ширине экрана ссылки в футере сильно растекаются в ширину, надо было ограничить ее, чтобы она примерно совпадала с шириной булшит блока.
Но это все в общем не очень значительные замечания, в общем сделано хорошо. Я уверен, что если анон будет дальше развиваться, читать книги по юзабилити и дизайну, изучать другие сайты, сидеть на дрибббле, он вполне сможет стать хорошим дизайнером.
А вот это вот серьезный косяк:
>\t<meta name="viewport" content="user-scalable=no">
Анон, ты явно откуда-то это скопировал и зря, ты делаешь свой сайт непригодным на мобильных устройствах. Где тут вообще логика, почему надо запрещать изменение масштаба?
Бутстрап мне кажется тут не особо нужен, так как от него в дизайне нет и следа, никакие виджеты не используются.
Вот объясните мне, как сделать это:
У меня есть time13.php нужно запускать его каждые 13 секунд доступ в ssh есть
На хабре какая-то длинная статья - я нихуя не понял. жаваскриптовский Set Time Out применить к пхпшному include time.php не получается. Что же делать?
> Все как один уныло копируют стандартные темы вордпресса
Может им просто мало денег платят и они спешат. А может конечно просто не умеют нормально делать.
> Кстати, вопрос по шрифтам. Можно ли сейчас использовать ну любой шрифт, какой я найду в интернете?
Тут есть вопрос авторского права. Ты не можешь просто так скопировать себе любой шрифт.
Но есть сайты вроде google fonts где собраны свободные для использования в интернетах шрифты.
Если ты хочешь хостить их на своем сайте, почитай статьи, разным браузерам нужны разные форматы, и надо писать специальный CSS код чтобы везде работало.
> Какие есть недостатки у такого подхода?
раньше мануал PHP использовал стандартный шрифт. Я щелкал по ссылке из гугла, он открывался и сразу был доступен. Теперь они решили поставить модные шрифты, которые в сумме (8 начертаний) весят больше мегабайта. Пока шрифт не загружен, браузер не отрисовывает текст. Часто бывает, что я кликаю по ссылке в гугле и секунд 5-10 смотрю на страницу без текста.
Это явно пример того, как делать не надо.
Но с другой стороны, если ты делаешь промосайт с оригинальным дизайном, там это уместно, но стоит заняться оптимизацией всего этого дела, есть разные способы, например вырезание лишних символов.
Косяки из-за того, что у меня по сути нет нормального PSD макета и я все по ходу делаю, прикидывая на глаз. Из-за этого приходится переделывать потом и про некоторые вещи забываю. В частности, изначально я хотел адаптивную версию делать, поэтому и использовал бутстрап. Но потом в процессе передумал.
Когда уже есть готовый макет со всем необходимым, то в разы проще все это делается, без всяких глупых косяков.
> Ты мне за неймспейсы не до конца пояснил
Я могу ошибаться, но по моему там написано что когда ты используешь динамический вызов класса или функции:
new $a
$b()
то ты должен использовать абсолютное имя, и текущий неймспейс к нему сам не добавляется.
Если бы ты писал так:
new Class
func()
То все бы работало как надо.
Я думаю, это происходит по той причине, что неймспейсы обрабатываются на этапе компиляции, PHP просто заменяет краткие имена на полные. А имя в твоей переменной он разумеется в этот момент заменить не может.
А, вот оно что. Акцент делался именно на динамическом вызове (это когда имя класса или функции является строкой, хранящейся в переменной, да?).
Мутный мануал, сложно что-то понять. Хотя конечно по сравнению с другими технологиями, где в доках даже не делается попыток что-то объяснить, этот еще ничего, да.
Эх, сплошная безблагодатность с такой учебой. Хорошо хоть ты иногда понятно объясняешь.
Ну по моему оригинал смотрится хуже.
Насчет font-face надо нагуглить правильный способ подключения, там довольно заморочная конструкция, где-то на хабре это есть (это может? правда довольно старая статья http://habrahabr.ru/post/113136/ ) и на fontsquirrel генератор хороий код генерирует.
>>510107
Ну да, но за запрет масштабирования все же тебе большой минус.
>>510102
Добавляешь в крон, или что лучше, в автозагрузку под супервизором вечноживущий php-скрипт который раз в 13 секунд запускает то что надо.
Ну и желательно какой-то таймаут сделать, чтобы он прибивал его при превышении времени или не запускал новую копию пока старая не завершится.
В помощь тебе posix функции:
http://php.net/manual/ru/book.posix.php
http://www.google.ru/search?aq=f&sourceid=chrome&ie=UTF-8&q=php+pcntl
Да бутстрап не нужен для адаптивности, вся адаптивность сводится к дописыванию нескольких @media правил. Мне кажется в твоем случае тебебольше училий приходится тратить на обход стилей бустрапа и с нуля было бы проще написать и код был бы чище.
Ну и я тебе советую еще почитать книги по юзабилити (если ты еще не читаешь). Дизайн это не только подбор шрифтов и цветов, это еще проектирование взаимодействия пользователя с приложением. Соответственно, если в нем не разбираться, можно сделать красивую, но не очень удобную форму.
Из того, что я сам читал, могу посоветовать:
Алан Купер, Психбольница — небольшая книга вводного уровня, которая в основном посвящена примерам неправильного проектирования и к чему это приводит, и на этих примерах автор наглядно показывает почему проектирование взаимодействия важная вещь.
Раскин, Интерфейс — книга небольшая, рассказывет про разные элементы компьютерных интферйесов и подходы к их проектированию. Раскин известный чел, он проектировал ОС для первых макинтошей и многие привычные элементы интерейса он же и придумал.
Он расскажет почему плохи режимы, как померять эффективность интерфейса, как подписывать кнопки, почему нам нужны гермафродитные кабели.
Ну и есть еще большая, толстая, подробная книга, это Алан Купер, об интерфейсе. Там рассказывается не только про элементы интерфйеса, но и про подходы к проектированию, например, про сценарии и персонажей.
Это те книги котрые у меня есть и которые я сам читал, наверно есть еще и другие.
Ну и еще я читал книгу «Живая Типографика», это книга про буквы и шрифты, она интересная, в ней много картинок и после ее прочтения такие шутки станут тебе очень понятны: https://pbs.twimg.com/media/BJlXnQzCUAQVo9_.jpg:large
А, и еще, советую смотреть работы других дизайнеров, на дрибббле, на behance.
что в while писать? он на пустых скобках ошибку выдает.
Короче я нихуя не понял, чо нужно делать и поставлю просто вот это
<META HTTP-EQUIV='Refresh' CONTENT='13; URL=time13.php'>
Тут же можно нубские вопросы создавать вот я и создам, что если я создам библиотеку со всеми словами что используются на сайте и в коде вместо них будет что-то вроде указателей насколько сократится разамер сайта и как повлияет на скорость загрузки? а что если подобной херней прострадать в плюсах (не веб)?
Поставь в «iframe», а нужен тебе был AJAX, со временем разберёшься.
Это уже сделали, называется архиватор. Ресурсы можно передавать по сети в сжатом виде, сервера умеют сжимать данные, а браузеры — распаковывать.
Почитай например про gzip — он делает то что ты описал
http://habrahabr.ru/post/221849/
http://habrahabr.ru/post/235553/
В общем такие вещи надо делать не руками, а автоматизиорованно.
Какое решение вижу я: после анализа переданных через форму данных скрипт записывает в переменную сообщения об ошибках (или о том, что всё верно) и тип самого сообщения (красное, зелёное). Эта переменная -- массив.
Вопрос: как правильнее передавать переменную между скриптами: через cookie+serialize(), а после вывода стирать куку или воспользоваться возможностями сессий?
Да, делаю задачу про студентов.
Мне тут нужно postgresql на debian поставить, а он вот что пишет
И локаль по пизде пошла, уже 3 часа тыкаюсь и поправить не могу
Помогите по старой памяти, госопда.
ОП мне советовал пользоваться его уроком по формам https://github.com/codedokode/pasta/blob/master/forms.md
Там не нужно будет передавать данные между скриптами
Всё равно не вижу, как реализовать это без передачи данных. Данные студента-то передавать между скриптами не требуется, да.
Но речь о других данных.
Вот сам класс: https://github.com/blackberryJam/abiturients/blob/master/app/classes/UserpageController.php
Закомменченный кусок кода -- создание описанного массива.
Я и говорю, что сами $errors и $values не надо передавать между скриптами, проверка на них должна быть в том же скрипте где и их заполнение.
А если я хочу их вывести в хтмл? values-то ладно, они в БД пишутся, вытащить можно. А errors?
Если нужно вывести сообщение об успешной регистрации (или о неправильно введенных данных), то можно отредиректить на ту же страницу гетом, а данные об успехе/ошибке передать через гет-переменную ?reg=ok или ?reg=error&field=fieldName&value=falseValue
В шаблоне уже подставлять значения ошибок. Например:
if (isset($_GET['error'])) {
if(isset($_GET['fieldName']) and isset($_GET['falseValue'])) {
$errorMsg = "Поле $fieldName может содержать только символы русского алфавита, вы ввели $falseValue";
}
}
Я бы сделал так. Но лучше подожди опа, я не уверен что это лучший способ.
Можно еще передавать данные через сессии и куки, но это муторно и неудобно, мне кажется.
>Можно еще передавать данные через сессии и куки, но это муторно и неудобно, мне кажется.
Почему неудобно? Ну куки -- да, там только строку можно передать (если не использовать serialize), а с сессиями, по-моему, очень просто: стартуем сессию, кладём данные в суперглобальный массив, вытаскиваем их в другом скрипте.
Подключи в конце скрипта шаблон формы где проверишь ошибки и выведешь их + $values
Если бы всё так было просто. У нас же после задания значений values и errors редирект и exit.
Ну так редирект идет на тот же файл, или нет?
В скрипте index.php можно написать
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// обработка запроса
}
// а здесь формируем шаблон для вывода. Данные об ошибке берешь либо из сессии, либо из гет-переменных, неважно.
>Данные об ошибке берешь либо из сессии, либо из гет-переменных, неважно.
Ну так вопрос и был в том, какой из способов наиболее оптимальный и правильный. Куки, сессии, гет-переменные или (лол) отдельная таблица под ошибки в БД?
Книг выходит очень много, вряд ли здесь найдется человек, который читал их все, эту в частности и может дать рецензию. Я посмотрел на рутрекере, хомячки вроде в восторге. Но говорят, что переведена кривовато.
А так mysql развивается не так бурно, как php например. Так что 2007 год вполне сойдет, 95% информации актуально.
За это время может добавились какие-то новые возможности, но если ты начинающий, то главное понять базовые вещи, а какие-то нововведения можно изучить потом.
Лично мне понравилась книга Бейли "Изучаем SQL" 2012 года, издательство O'Reilly.
Очень большой акцент делается именно на когнитивной части, то есть чтобы учащемуся было приятно и интересно (хотя со смищными картинками они перестарались конечно). Есть на торрентах.
Когда дойдешь до изучения более сложных вещей, тех же юниксов например, офигеешь от отвратительной подачи материала.
На учащегося вываливают гору бессвязной справочной информации, мол сиди и зубри наизусть. На такое согласится только совсем опущенный унтерменш без личной жизни.
>А так mysql развивается не так бурно, как php например. Так что 2007 год вполне сойдет, 95% информации актуально.
Да, я и имел ввиду это, спс
Прочел мой урок про формы? Ты редиректишь только при успешной обработке формы (чтобы при обновлении страницы запрос не отсылался). при ошибке надо не редиректить, а выводишь форму с ошибками.
А ты редиректишь всегда. Из-за этого и проблемы. Посомтри алогритм обработки форм внимательно, там мы при ошибке не редиректим.
Ок, понял.
Не могу сообразить, как у них в api v3 все работает, и где мой php класс.
Очень надо.
Это плохой способ, так как при редиректе мы теряем введенные в поля значения. У меня в уроке про формы описан алгоритм, почему бы просто не сделать как там написано? Все тогда будет работать.
Решения с куками, сессиями и таблицами не пройдут, и не надейтесь. Нечего велосипедостроительством заниматься.
http://special.habrahabr.ru/slemma/
А что текст в 3Д лучше читается чем плоский?
Алсо у меня например WebGL не работает на ноуте вообще. Так как видеокарта не поддерживается. ТОлько CSS трансформации работают, но без аппаратного ускорения.
Для логотипчиков и иконок вполне можно. По-моему неплохо
>Решения с куками, сессиями и таблицами не пройдут, и не надейтесь. Нечего велосипедостроительством заниматься.
С выводом ошибок проблемы нет.
А если мы хотим вывести сообщение о том, что данные успешно добавлены/обновлены? После редиректа.
Есть варианты с использованием кук/сессий (flash сообщения), а можно просто при редиректе параметр добавлять: /index.php?message=saved
>flash сообщения
Тогда такой вариант нормален?
setcookie('messageSuccess', $messageSuccess, time() + 600);
header('Location: ...');
exit;
А вывод делаем таким:
if (array_key_exists('messageSuccess', $_COOKIE)) {
render($_COOKIE['messageSuccess']);
setcookie('messageSuccess', '', time() - 1);
} else {
render();
}
Только не стоит вписывать систему сообщений прямо в код. Сделай функции или методы для установки сообщения, прочтения сообщения, удаления. Также, вместо текста сообщения лучше хранить идентификатор, так как объем кук ограничен.
Куки имеют недостаток, что они менее надежны (например: при загрузке страницы произошла ошибка, пользователь обновил страницу, но сообщение он уже не увидит) и что они общие для всех табов, и в неудачном случае сообщение от одного таба может вывестись в другом (хотя это конечно надо постараться так сделать).
Значит, правильнее использовать сессии аналогичным образом? Сохранять, а после вывода чистить.
Так сессии тоже общие для всех вкладок и точно также сообщение не будет прочитано при ошибке загрузки страницы.
Исправить проблему с выводом сообщения при обрывах связи можно, если удалять сообщение не на севрере, а на клиенте, яваскриптом, после того как страница точно загрузилась. Но по моему не стоит с этим заморачиваться, это лишнее усложнение, в принципе не очень страшно если уведомление потеряется.
Я, наверное, пока уберу все эти цветные плашки. Просто текстом ошибки выведу. А успешно отредактировалось или нет -- и так видно по содержанию формы.
Нет, надо бы сделать уведомление. Потому что когда ты просто получаешь форму, непонятно все ли в порядке или это баг какой-то.
> Я, наверное, пока уберу все эти цветные плашки. Просто текстом ошибки выведу.
А это зачем? Мы же вроде говорили про flash уведомления, а не про ошибки в форме.
Ну сначала у меня была мысль сделать общий механизм как для успешного варианта отправки формы, так и не успешного (с выводом ошибок).
Но теперь сделаю вывод ошибок как в уроке, а генерировать успешное сообщение будет другая часть кода.
Например
Connection:Keep-Alive
Гугл перекинул меня на википедию https://ru.wikipedia.org/wiki/Постоянное_HTTP-соединение
Постоянное HTTP-соединение — использование одного TCP-соединения для отправки и получения множественных HTTP-запросов и ответов вместо открытия нового соединения для каждой пары запрос-ответ.
Учитывая, что я не знаю что такое TCP-соединение, мне это мало о чем говорит. Я догадываюсь, что соединяясь с указанным хостом example.com, клиент будет запрашивать все последующие ресурсы (картинки, стили, скрипты) через одно и то же соединение, а не открывать каждый раз новое.
По ссылке про TCP в вики совсем непонятная фигня.
ОП, кроме талмуда Олифер по сетевым технологиям, есть чо покороче? Я посмотрел по оглавлению, TCP объясняется на 482 странице, я дошел только до 58. Я так с голоду помру, пока дочитаю. А пропускать скорее всего нельзя, иначе будет непонятно.
curl -v http://test/hello.php
Hostname was NOT found in DNS cache
Trying 127.0.0.1...
Connected to test (127.0.0.1) port 80 (#0)
Это и DNS-адреса где-то кешируются получается?
> GET /hello.php HTTP/1.1
> User-Agent: curl/7.35.0
> Host: test
/> Accept:
Что такое Accept /* ?
О, нашел какой-то симпатичный бложек по http. Надо почитать. ОП, посмотри опытным взором, хороший источник или нет:
http://www.http11.ru/
Дизайн выглядит приятно (это важно, я не буду читать неотформатированную стену текста), и вроде бы аффтар жжот.
Например
Connection:Keep-Alive
Гугл перекинул меня на википедию https://ru.wikipedia.org/wiki/Постоянное_HTTP-соединение
Постоянное HTTP-соединение — использование одного TCP-соединения для отправки и получения множественных HTTP-запросов и ответов вместо открытия нового соединения для каждой пары запрос-ответ.
Учитывая, что я не знаю что такое TCP-соединение, мне это мало о чем говорит. Я догадываюсь, что соединяясь с указанным хостом example.com, клиент будет запрашивать все последующие ресурсы (картинки, стили, скрипты) через одно и то же соединение, а не открывать каждый раз новое.
По ссылке про TCP в вики совсем непонятная фигня.
ОП, кроме талмуда Олифер по сетевым технологиям, есть чо покороче? Я посмотрел по оглавлению, TCP объясняется на 482 странице, я дошел только до 58. Я так с голоду помру, пока дочитаю. А пропускать скорее всего нельзя, иначе будет непонятно.
curl -v http://test/hello.php
Hostname was NOT found in DNS cache
Trying 127.0.0.1...
Connected to test (127.0.0.1) port 80 (#0)
Это и DNS-адреса где-то кешируются получается?
> GET /hello.php HTTP/1.1
> User-Agent: curl/7.35.0
> Host: test
/> Accept:
Что такое Accept /* ?
О, нашел какой-то симпатичный бложек по http. Надо почитать. ОП, посмотри опытным взором, хороший источник или нет:
http://www.http11.ru/
Дизайн выглядит приятно (это важно, я не буду читать неотформатированную стену текста), и вроде бы аффтар жжот.
Отзовитесь, няши.
inb4: не туда зашёл
Сейчас кратко расскажу что такое TCP (и как работает интернет). По умолчанию, протокол IP на котором построен интернет, имеет такие особенности:
— узлы сети могут обмениваться небольшими (до 1.5Кб) пакетами друг с другом
— каждая подключеннная к сети сетевая карта имеет уникальный IP адрес, который позволяет определить отправителя/получателя пакета. заметь, я пишу «каждая сетевая карта» так как у узла может быть несколько сетевых карт, причем подключенных к разным или одной сети
— пакеты доставляются по принципу «best effort», нет гарантий что пакеты придут в том же порядке в котром отправлены, и что они придут вообще
Конечно возможность обмениваться пакетами с любым узлом сети в мире это хорошо и в даже наверно можно считать научным достижением, но с такой системой работать неудобно. Что если тебе надо послать информации больше чем 1.5 килобайта? Как пересылать большие файлы? Что делать если пакет не придет? Если на компьютере запущено несколько работающих с сетью программ, как понять для какой из них пришел пакет? Как сделать двунаправленный надежный канал передачи?
Для решения этих проблем сделаны более высокоуровневые протоколы.
Проблема маленьких пакетов решается тем, что информация разбивается на части и в пакет пишется номер этой части (заметь что по прежнему есть проблема, а что если одна из частей не придет?). Проблема какой программе адресован пакет решается добавлением в пакет числа — номера порта. Программа, желающая работать с сетью, резервирует в ОС уникальный номер порта для себя («открывает порт»).
Ты еще можешь услышать термин «сокет». Сокет — это специальная структура, которая описывает UDP или TCP соединение между 2 узлами и соединение идентифицируется 2 IP адресами и 2 номерами портов (получателя и отправителя). То есть UDP и TCP соединения устанавливаются между программой-отправителем и получателем, а не просто узлами.
Вот эти протоколы:
— сигнальный (сигнальный значит что он не передает файлы и данные, а только сообщения вроде того что узел недоступен) протокол ICMP — он позволяет передавать в IP пакетах информационные сообщения, например роутер может отправить сообщение о том что узел-адресат недоступен. Команды ping/traceroute (проверка доступности хоста и проверка каким путем идут пакеты), про которые ты наверно слышал, работают, посылая ICMP echo request пакеты, на которые хосты отвечают. ICMP не использует порты.
Он неплохо описан тут: https://ru.wikipedia.org/wiki/ICMP
— протокол передачи датаграмм UDP. Этот протокол позволяет отправить датаграмму (кусок данных) на указанный порт указанного узла. Он разбивает датаграмму на части, передает в виде нескольких IP пакетов, а на другом узле собирает. Если один из пакетов не пришел, то UDP отбрасывает его. UDP таким образом не гарантирует доставку, но решает проблему маленьких пакетов приходящих в случайном порядке. UDP используется там где нужна минимальная задержка, а потери данных приемлемы — передача голоса, видео в скайпе, сетевые игры
— протокол TCP. Это надежный протокол, который организует двунаправленный канал связи с заданным портом на заданном узле. Он позволяет пересылать по этому каналу в обе стороны поток данных неограниченной длины. TCP также исплоьзует подтверждение полученных данных и повторную пересылку пакетов при их потере. Скорость передачи подбирается автоматически в зависимости от скорости сети и числа потерь пакетов. Платить за это приходится чуть большей задержкой, так как при TCP мы должны ждать подтверждения того, что удаленный узел получил данные. TCP исплоьзуется в большинстве других протоколов, в том числе HTTP.
Заметь, главная разница в том что UDP просто шлет датаграммы, без подтверждений что они получены, а TCP устанавлвивает именно надежный канал передачи данных, который либо передает данные без ошибок, либо разрывается (и отправитель об этом знает).
Ну и передача видео/голоса по TCP плохая идея, так как тот при утере пакета сначала какое-то время ждет пока он придет, а потом отправляет просьбу выслать его повторно, и если этот пакет с просьбой теряется, то мы получаем еще большую задежрку. Потому голос/видео передают по UDP, причем используются такие кодеки, которые могут работать при потере части данных, ухудшая при этом качество картинки/звука.
Собственно возвращаясь к Keep_Alive. Без него для каждого нового запроса создается новое TCP соединение. С ним мы переиспользуем существющее соединение, посылая новый запрос после получения ответа от сервера. Также, есть pipelining — это когда отправитель шлет запросы не дожидаясь получения ответа, и соответственно потом получает несклоько ответов сразу.
Профит в том что мы экономим время на установку нового соединения, котрое требует обмен 3 пакетами (TCP handshake). Если пакет идет допустим из России в США 100 мс, то 3 пакета это 300 мс.
Для того чтобы это работало, получатель должен как-то понять что сервер закончил передавать данные (по умочланию признаком завершения является закрытие соединения сервером). для этого сервер должден либо указать длину тела ответа с помощью Conetnt-Length, либо использовать способ передачи вроде TRansfter-Encoding: chunked который содержит признак конца данных.
Бложек выглядит нормально но он по моему просто заточен под набирание веса в Гугле.
Почитай-ка вот эти статьи, они конечно по отдельности не идеальны, но вместе, я думаю, дают общую картину:
http://kunegin.com/ref3/tcp/glava4.htm
http://habrahabr.ru/post/209144/
http://book.itep.ru/4/44/udp_442.htm
http://www.chin28.narod.ru/d10.1.htm
Для полного понимания конечно было бы хорошо написать программу-клиент и программу-сервер, которые бы обменивались UDP датаграммами или общались через TCP соединение. Например, что-нибудь вроде чата между 2 консольными программами. Это было бы конечно полезно, но я не знаю, есть ли у тебя на жто время.
Но позже если ты например захочешь изучить вебсокеты, знание TCP и сетевого программирования было бы полезно.
В качестве мини-практики можешь сделать такие вещи:
— попробуй попинговать узлы ya.ru, google.com командой вроде ping goog.com
— попробуй определить путь к узлу, исплоьзуя команду tracert google.com (traceroute если у тебя линукс/мак)
— попробуй соединиться с каким-либо узлом и вручную сделать HTTP-запрос. Для этого установи telnet-соединение (протокол telnet это почти что голый TCP и таким образом команда telnet дает нам TCP канал с указанными хостом/портом) командой
telnet ya.ru 80
Порт 80 это порт используемый по умолчанию для http.
затем набери
GET / HTTP/1.0 (Enter)
Host: ya.ru (Enter)
(Enter)
И получи ответ. Набирать надо быстро (там есть таймаут), если ты не уверен что справишься, можешь набрать текст в редакторе и скопировать.
Если telnet плохо работает или еще чем-то тебе не нравится, можно скачать программу putty (под Windows) или netcat (под линукс) и работать через нее.
Времени это много не занимает, но попробовать сделать HTTP запрос полезно чтоыб лучше понять этот протокол. Попробуй почувстовать себя в роли браузера.
Сейчас кратко расскажу что такое TCP (и как работает интернет). По умолчанию, протокол IP на котором построен интернет, имеет такие особенности:
— узлы сети могут обмениваться небольшими (до 1.5Кб) пакетами друг с другом
— каждая подключеннная к сети сетевая карта имеет уникальный IP адрес, который позволяет определить отправителя/получателя пакета. заметь, я пишу «каждая сетевая карта» так как у узла может быть несколько сетевых карт, причем подключенных к разным или одной сети
— пакеты доставляются по принципу «best effort», нет гарантий что пакеты придут в том же порядке в котром отправлены, и что они придут вообще
Конечно возможность обмениваться пакетами с любым узлом сети в мире это хорошо и в даже наверно можно считать научным достижением, но с такой системой работать неудобно. Что если тебе надо послать информации больше чем 1.5 килобайта? Как пересылать большие файлы? Что делать если пакет не придет? Если на компьютере запущено несколько работающих с сетью программ, как понять для какой из них пришел пакет? Как сделать двунаправленный надежный канал передачи?
Для решения этих проблем сделаны более высокоуровневые протоколы.
Проблема маленьких пакетов решается тем, что информация разбивается на части и в пакет пишется номер этой части (заметь что по прежнему есть проблема, а что если одна из частей не придет?). Проблема какой программе адресован пакет решается добавлением в пакет числа — номера порта. Программа, желающая работать с сетью, резервирует в ОС уникальный номер порта для себя («открывает порт»).
Ты еще можешь услышать термин «сокет». Сокет — это специальная структура, которая описывает UDP или TCP соединение между 2 узлами и соединение идентифицируется 2 IP адресами и 2 номерами портов (получателя и отправителя). То есть UDP и TCP соединения устанавливаются между программой-отправителем и получателем, а не просто узлами.
Вот эти протоколы:
— сигнальный (сигнальный значит что он не передает файлы и данные, а только сообщения вроде того что узел недоступен) протокол ICMP — он позволяет передавать в IP пакетах информационные сообщения, например роутер может отправить сообщение о том что узел-адресат недоступен. Команды ping/traceroute (проверка доступности хоста и проверка каким путем идут пакеты), про которые ты наверно слышал, работают, посылая ICMP echo request пакеты, на которые хосты отвечают. ICMP не использует порты.
Он неплохо описан тут: https://ru.wikipedia.org/wiki/ICMP
— протокол передачи датаграмм UDP. Этот протокол позволяет отправить датаграмму (кусок данных) на указанный порт указанного узла. Он разбивает датаграмму на части, передает в виде нескольких IP пакетов, а на другом узле собирает. Если один из пакетов не пришел, то UDP отбрасывает его. UDP таким образом не гарантирует доставку, но решает проблему маленьких пакетов приходящих в случайном порядке. UDP используется там где нужна минимальная задержка, а потери данных приемлемы — передача голоса, видео в скайпе, сетевые игры
— протокол TCP. Это надежный протокол, который организует двунаправленный канал связи с заданным портом на заданном узле. Он позволяет пересылать по этому каналу в обе стороны поток данных неограниченной длины. TCP также исплоьзует подтверждение полученных данных и повторную пересылку пакетов при их потере. Скорость передачи подбирается автоматически в зависимости от скорости сети и числа потерь пакетов. Платить за это приходится чуть большей задержкой, так как при TCP мы должны ждать подтверждения того, что удаленный узел получил данные. TCP исплоьзуется в большинстве других протоколов, в том числе HTTP.
Заметь, главная разница в том что UDP просто шлет датаграммы, без подтверждений что они получены, а TCP устанавлвивает именно надежный канал передачи данных, который либо передает данные без ошибок, либо разрывается (и отправитель об этом знает).
Ну и передача видео/голоса по TCP плохая идея, так как тот при утере пакета сначала какое-то время ждет пока он придет, а потом отправляет просьбу выслать его повторно, и если этот пакет с просьбой теряется, то мы получаем еще большую задежрку. Потому голос/видео передают по UDP, причем используются такие кодеки, которые могут работать при потере части данных, ухудшая при этом качество картинки/звука.
Собственно возвращаясь к Keep_Alive. Без него для каждого нового запроса создается новое TCP соединение. С ним мы переиспользуем существющее соединение, посылая новый запрос после получения ответа от сервера. Также, есть pipelining — это когда отправитель шлет запросы не дожидаясь получения ответа, и соответственно потом получает несклоько ответов сразу.
Профит в том что мы экономим время на установку нового соединения, котрое требует обмен 3 пакетами (TCP handshake). Если пакет идет допустим из России в США 100 мс, то 3 пакета это 300 мс.
Для того чтобы это работало, получатель должен как-то понять что сервер закончил передавать данные (по умочланию признаком завершения является закрытие соединения сервером). для этого сервер должден либо указать длину тела ответа с помощью Conetnt-Length, либо использовать способ передачи вроде TRansfter-Encoding: chunked который содержит признак конца данных.
Бложек выглядит нормально но он по моему просто заточен под набирание веса в Гугле.
Почитай-ка вот эти статьи, они конечно по отдельности не идеальны, но вместе, я думаю, дают общую картину:
http://kunegin.com/ref3/tcp/glava4.htm
http://habrahabr.ru/post/209144/
http://book.itep.ru/4/44/udp_442.htm
http://www.chin28.narod.ru/d10.1.htm
Для полного понимания конечно было бы хорошо написать программу-клиент и программу-сервер, которые бы обменивались UDP датаграммами или общались через TCP соединение. Например, что-нибудь вроде чата между 2 консольными программами. Это было бы конечно полезно, но я не знаю, есть ли у тебя на жто время.
Но позже если ты например захочешь изучить вебсокеты, знание TCP и сетевого программирования было бы полезно.
В качестве мини-практики можешь сделать такие вещи:
— попробуй попинговать узлы ya.ru, google.com командой вроде ping goog.com
— попробуй определить путь к узлу, исплоьзуя команду tracert google.com (traceroute если у тебя линукс/мак)
— попробуй соединиться с каким-либо узлом и вручную сделать HTTP-запрос. Для этого установи telnet-соединение (протокол telnet это почти что голый TCP и таким образом команда telnet дает нам TCP канал с указанными хостом/портом) командой
telnet ya.ru 80
Порт 80 это порт используемый по умолчанию для http.
затем набери
GET / HTTP/1.0 (Enter)
Host: ya.ru (Enter)
(Enter)
И получи ответ. Набирать надо быстро (там есть таймаут), если ты не уверен что справишься, можешь набрать текст в редакторе и скопировать.
Если telnet плохо работает или еще чем-то тебе не нравится, можно скачать программу putty (под Windows) или netcat (под линукс) и работать через нее.
Времени это много не занимает, но попробовать сделать HTTP запрос полезно чтоыб лучше понять этот протокол. Попробуй почувстовать себя в роли браузера.
Яндексом повеяло. Причем я сначала подумал что это и есть элементы яндекса, пока не прочитал пост.
Так и есть. Часть из них спиздил здеся, но я хочу сиэсэски допилить напильником.
https://ru.bem.info/libs/bem-components/v2.2.1/
Сделай страницу где слева будет виджет, а справа готовый HTML c ним. Такую страницу можно генерировать автоматически если например хранить код каждого виджета в отдельном файле. Я видел такие штуки, и это довольно удобно.
И кстати, раз ты используешь БЭМ-компоненты, можно генерировать эту страницу сразу из них. Это можно делать на PHP или node.js, что тебе ближе.
>Сейчас кратко расскажу...
>6973 символа
Ты в своем репертуаре. Надеюсь, это паста, и ты не писал это руками.
Блин, придется читать, человек мне это писал, старался знаешь.
Давай я сокращу это и выпишу в конспект основные тезисы:
По IP протоколу узлы (т.е. физ.устройства, сетевые карты) могут обмениваться малыми объемами данных (пакетами). Пакеты как-то неудачно нумеруются, приходят не обязательно в том порядке, что их отправили, и вообще часть может быть потеряна.
Так.
Для устранения вышеупомянутых проблем есть протоколы более высокого уровня типа ICMP, UPD и TCP. Данными обмениваются теперь не узлы (сетевые карты), а специальный софт, программное обеспечение. Ну вот как у нас есть взаимодействие клиент-сервер (мозилла-апач, например).
Пока смутно понимаю, что такое порт. Это что-то вроде идентификатора соединения в сетевой карте?
Таким образом, при работе по ICMP протоколу получается программки даже не открывают соединение с узлом(я так понял, имеется ввиду сетевая карта), у серверочка (как его зовут?) только запрашивается служебная информация: есть ли возможность создать соединение (открыть порт), или нет.
Дальше. UPD уже позволяет отправить какие-то данные на указанный порт указанного узла (сет.карты), где эти данные уже разбиваются на маленькие пакеты и скармливаются IP протоколу. Таким образом UPD выступает как бы посредником, оберткой над этим делом. Решает проблему упорядоченности данных, но не решает проблему потери.
TCP отличается надежностью, шлет повторные запросы на пропавшие пакеты, таким образом гарантируется целостность, пусть и ценой потери некоторой скорости.
>при keep-alive отправитель шлет запросы не дожидаясь получения ответа, и соответственно потом получает несклоько ответов сразу.
А когда соединение разрывается? Как происходит этот процесс? Ну вот у меня запрос на GET /index.php HTTP/1.1
Устанавливается TCP-соединение с example.com. Приходит полностью html или другой контент, который нам вернул php. А дальше браузер видит ссылочку на стили:
/css/main.css
Соответственно ему нужно получить и этот файл, потом картинки и т.д.
Так вот, если первый запрос завершился 200 OK, то соединение продолжает некоторое время висеть открытым, или как? Как он умудряется получив данные от index.php по тому же каналу, или соединению получить прочие ресурсы? Или браузер закроет соединение только полностью отрисовав в памяти DOM?
Если спустя время пользователь кликнет по кнопочке, на которой у меня висит аякс-запрос, то это будет уже новое соединение?
>Для полного понимания конечно было бы хорошо написать программу-клиент и программу-сервер, которые бы обменивались UDP датаграммами
Ты меня с кем-то путаешь. Это слишком сложно, и я не знаю тех языков, на которых подобное пишется (си, я подозреваю).
Ссылки как обычно схоронил, завтра уже почитаю. Ты меня своей пастой сильно утомил, еще какие-то левые статьи читать.
>попробуй попинговать узлы ya.ru
ну пик1. Что мне с ним дальше делать? Я вижу размер пакета (64 байта), айпи яндекса (93.158.134.3), номер пакета, время установки соединения (ну или эмуляции этого соединения, мы же с портом не коннектимся), и какой-то ttl.
>traceroute
выдало
1. x x x (три звездочки)
2. x x x (три звездочки)
3. какой-то url и айпи, скорее всего провайдера 30.702 ms 30.731 ms 30.718 ms
4. похожая строка
5. x x x (три звездочки)
6. 173.194.113.201 (173.194.113.201) 32.533 ms 11.306 ms 11.851 ms
Чего он мне гугл только с пятой попытки нашел?
telnet ya.ru 80
Говорит 400 bad request
>Сейчас кратко расскажу...
>6973 символа
Ты в своем репертуаре. Надеюсь, это паста, и ты не писал это руками.
Блин, придется читать, человек мне это писал, старался знаешь.
Давай я сокращу это и выпишу в конспект основные тезисы:
По IP протоколу узлы (т.е. физ.устройства, сетевые карты) могут обмениваться малыми объемами данных (пакетами). Пакеты как-то неудачно нумеруются, приходят не обязательно в том порядке, что их отправили, и вообще часть может быть потеряна.
Так.
Для устранения вышеупомянутых проблем есть протоколы более высокого уровня типа ICMP, UPD и TCP. Данными обмениваются теперь не узлы (сетевые карты), а специальный софт, программное обеспечение. Ну вот как у нас есть взаимодействие клиент-сервер (мозилла-апач, например).
Пока смутно понимаю, что такое порт. Это что-то вроде идентификатора соединения в сетевой карте?
Таким образом, при работе по ICMP протоколу получается программки даже не открывают соединение с узлом(я так понял, имеется ввиду сетевая карта), у серверочка (как его зовут?) только запрашивается служебная информация: есть ли возможность создать соединение (открыть порт), или нет.
Дальше. UPD уже позволяет отправить какие-то данные на указанный порт указанного узла (сет.карты), где эти данные уже разбиваются на маленькие пакеты и скармливаются IP протоколу. Таким образом UPD выступает как бы посредником, оберткой над этим делом. Решает проблему упорядоченности данных, но не решает проблему потери.
TCP отличается надежностью, шлет повторные запросы на пропавшие пакеты, таким образом гарантируется целостность, пусть и ценой потери некоторой скорости.
>при keep-alive отправитель шлет запросы не дожидаясь получения ответа, и соответственно потом получает несклоько ответов сразу.
А когда соединение разрывается? Как происходит этот процесс? Ну вот у меня запрос на GET /index.php HTTP/1.1
Устанавливается TCP-соединение с example.com. Приходит полностью html или другой контент, который нам вернул php. А дальше браузер видит ссылочку на стили:
/css/main.css
Соответственно ему нужно получить и этот файл, потом картинки и т.д.
Так вот, если первый запрос завершился 200 OK, то соединение продолжает некоторое время висеть открытым, или как? Как он умудряется получив данные от index.php по тому же каналу, или соединению получить прочие ресурсы? Или браузер закроет соединение только полностью отрисовав в памяти DOM?
Если спустя время пользователь кликнет по кнопочке, на которой у меня висит аякс-запрос, то это будет уже новое соединение?
>Для полного понимания конечно было бы хорошо написать программу-клиент и программу-сервер, которые бы обменивались UDP датаграммами
Ты меня с кем-то путаешь. Это слишком сложно, и я не знаю тех языков, на которых подобное пишется (си, я подозреваю).
Ссылки как обычно схоронил, завтра уже почитаю. Ты меня своей пастой сильно утомил, еще какие-то левые статьи читать.
>попробуй попинговать узлы ya.ru
ну пик1. Что мне с ним дальше делать? Я вижу размер пакета (64 байта), айпи яндекса (93.158.134.3), номер пакета, время установки соединения (ну или эмуляции этого соединения, мы же с портом не коннектимся), и какой-то ttl.
>traceroute
выдало
1. x x x (три звездочки)
2. x x x (три звездочки)
3. какой-то url и айпи, скорее всего провайдера 30.702 ms 30.731 ms 30.718 ms
4. похожая строка
5. x x x (три звездочки)
6. 173.194.113.201 (173.194.113.201) 32.533 ms 11.306 ms 11.851 ms
Чего он мне гугл только с пятой попытки нашел?
telnet ya.ru 80
Говорит 400 bad request
> Пакеты как-то неудачно нумеруются,
Пакеты не нумеруются в протоколе IP вообще никак, это делается в UDP/TCP, чтобы понять в каком порядке их потом собирать, когда они придут. Как иначе?
> Пока смутно понимаю, что такое порт. Это что-то вроде идентификатора соединения в сетевой карте?
Это число от 1 до 65535. Он есть только в UDP и TCP. Когда программа хочет принимать UDP или TCP, она говорит ОС: я хочу открыть TCP порт 2000 на прием. И ОС может ответить одно их двух:
— ок, порт открыт, держи сокет (идентификатор), все датаграммы (или соединения) пришедшие на этот порт ты будешь получать через этот сокет.
— нет, этот порт уже занят другой программой (такое получается если ты например пытаешься запустить Апач второй раз при уже запущенном)
А если программа (клиент) хочет передавать датаграммы или установить соединенеи, то ОС дает ей любой свободный номер порта, так как тут не принципиально какой он будет.
Например порт 80 испольузется по умолчанию в HTTP и например программа-веб-сервер на сайте ждет соединений именно на него. На других портах какие-то другие программы или ничего нет.
Вот список некоторых общеизвестных номеров портов: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BF%D0%BE%D1%80%D1%82%D0%BE%D0%B2_TCP_%D0%B8_UDP
Номера в списке выдает организация IANA, но ты можешь исплозьзовать любые, просто список это скорее рекомендация разрабочтикам, чтобы они, делая свой новый протокол не использовали уже занятый порт, ведь тогда их программа будет конфликтовать с другими на том же компьютере.
Под линуксом и маком порты ниже 1024 может открыть только программа с правами администратора. Это сделано для защиты от таких ситуаций:
— программа-сервер ssh (удаленный доступ к командной строке на линуксе), слушающая порт 21, упала из-за ошибки и порт освободился (или например веб-сервер Апач на 80 порту упал из-за ошибки)
— злоумышленник-пользователь сервера, не имеющий прав администратора, запустил свою программу слушающую этот порт и собирающущую пароли и любые данные которые слали Апачу/ssh. Заняв порт он не дает ssh/Апачу открыть его после перезапуска.
Ну к примеру на хостинге много обычных пользователей и нельзя чтобы они могли открыть порт вместо Апача или ssh.
Таким образом если номер порта меньше 1024 то ты знаешь что программа на нем запущена администратором сервера, а не обычным пользователем.
> Это что-то вроде идентификатора соединения в сетевой карте?
Нет, это на уровне ОС, у нее есть список какой порт какой программой открыт и соответственно кому надо передавать пришедшие на этот порт данные. Сетевая карта работает на более низком уровне и просто передает ОС пришедшие пакеты не особо в них разбираясь.
> Таким образом, при работе по ICMP протоколу получается программки даже не открывают соединение с узлом(я так понял, имеется ввиду сетевая карта), у серверочка (как его зовут?) только запрашивается служебная информация: есть ли возможность создать соединение (открыть порт), или нет.
Это при UDP/TCP так. Программа-сервер открывает порт для приема соединений либо программа-клиент просит ОС установить соединение с данными Ip/портом.
В ICMP портов нет и понять какой программе адресован пакет невозможно. Потому под линуксом программа ping использует права администратора, чтобы заставить ОС отдавать ей все пришедшие ICMP-пакеты (без прав админа это сделать нельзя разумеется). Если ты запустишь несколько ping одновременно, они не путаются, так как добавляют в пакеты какие-то свои номера, но это не порт.
Порт идентифицирует программу, не соединение. Соединение идентифицирует 4 числа: IP отправителя/получаетля, порт отправителя/получателя. Таким образом, один порт может использоваться для множества соединений. Например веб-сервер может принимать одновременно сотни соединений на один порт 80 при условии что они приходят от разных IP/портов.
То есть у веб-сервера который слушает порт 80, обычно есть много сокетов (сокет это что-то вроде идентификатора соединения на уровне ОС):
— «слушающий сокет» на порт 80, через который он получает от ОС новые сокеты при подсоединении клиентов к этому порту
— сокеты установленных соединений с клиентами
(это уже особенности того как работает ОС)
> приходят не обязательно в том порядке, что их отправили,
Да, потому что пакеты могут идти разными путями, а также маршрутизатор может по каким-то причинам пересылать их в другом порядке.
> UPD уже позволяет отправить какие-то данные на указанный порт указанного узла (сет.карты), где эти данные уже разбиваются на маленькие пакеты и скармливаются IP протоколу.
У сетевой карты нет портов, порт это просто число по которому ОС идентифицирует программу. У сетевого интерфейса есть только IP адрес и он отправляет/принимает все подряд.
> А когда соединение разрывается? Как происходит этот процесс?
В TCP соединение закрывать может передающая сторона, причем закрывает она этим канал только в одну сторону, на передачу. К примеру, клиент, послав запрос может сразу закрыть канал от клиента к серверу, но оставить открытым канал в обратную сторону (а каждое соединение, как ты помнишь двунаправленное).
Если закрыть канал в обе стороны, очевидно, соединение считается полностью закрытым.
Закрытие делается отправкой специального TCP-пакета с флагом FIN. Он значит «я закончил передавать данные». Получив такой пакет, другая сторона отправляет пакет с флагами FIN + ACK, то есть подтверждает закрытие одного из направлений передачи данных.
Также, есть сброс соединения. Он делается пакетом RST. Он обозначает либо отказ устанавливать соединение, либо если послан после установки, обозначает разрыв соединения. ОС шлет пакеты RST в случае если:
— пришел пакет с попыткой установить соединение на несуществующий порт, на котором никто не слушает (также можно настроить ОС чтобы она ничего не отправляла в ответ, для защиты от сканирования портов)
— программа, которая открыла порт, упала/завершилась. В этом слуае ОС закрывает все открытые ей соединения, посылая пакеты RST
Вот есть длинная, но с графиками, статья про виды пакетов TCP:
http://www.soslan.ru/tcp/tcp18.html
http://www.opennet.ru/docs/RUS/tcpip/#c4_tcp
Кстати, есть программы которые позволяют перрехватывать проходящие через сетевую карту пакеты. Например кроссплатформенный и бесплатный wireshark (с графическим интерфейсом). Можешь поставить его и попробовать, только закрой лишние программы а то будет трудно разобраться. В нем будут видны все свойства пакетов, флаги, порядок установки и разрыва соединения.
Также, команда netstat -abn покажет все открытые соединения и слушающие порты. попробуй ее запустить.
> Пакеты как-то неудачно нумеруются,
Пакеты не нумеруются в протоколе IP вообще никак, это делается в UDP/TCP, чтобы понять в каком порядке их потом собирать, когда они придут. Как иначе?
> Пока смутно понимаю, что такое порт. Это что-то вроде идентификатора соединения в сетевой карте?
Это число от 1 до 65535. Он есть только в UDP и TCP. Когда программа хочет принимать UDP или TCP, она говорит ОС: я хочу открыть TCP порт 2000 на прием. И ОС может ответить одно их двух:
— ок, порт открыт, держи сокет (идентификатор), все датаграммы (или соединения) пришедшие на этот порт ты будешь получать через этот сокет.
— нет, этот порт уже занят другой программой (такое получается если ты например пытаешься запустить Апач второй раз при уже запущенном)
А если программа (клиент) хочет передавать датаграммы или установить соединенеи, то ОС дает ей любой свободный номер порта, так как тут не принципиально какой он будет.
Например порт 80 испольузется по умолчанию в HTTP и например программа-веб-сервер на сайте ждет соединений именно на него. На других портах какие-то другие программы или ничего нет.
Вот список некоторых общеизвестных номеров портов: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BF%D0%BE%D1%80%D1%82%D0%BE%D0%B2_TCP_%D0%B8_UDP
Номера в списке выдает организация IANA, но ты можешь исплозьзовать любые, просто список это скорее рекомендация разрабочтикам, чтобы они, делая свой новый протокол не использовали уже занятый порт, ведь тогда их программа будет конфликтовать с другими на том же компьютере.
Под линуксом и маком порты ниже 1024 может открыть только программа с правами администратора. Это сделано для защиты от таких ситуаций:
— программа-сервер ssh (удаленный доступ к командной строке на линуксе), слушающая порт 21, упала из-за ошибки и порт освободился (или например веб-сервер Апач на 80 порту упал из-за ошибки)
— злоумышленник-пользователь сервера, не имеющий прав администратора, запустил свою программу слушающую этот порт и собирающущую пароли и любые данные которые слали Апачу/ssh. Заняв порт он не дает ssh/Апачу открыть его после перезапуска.
Ну к примеру на хостинге много обычных пользователей и нельзя чтобы они могли открыть порт вместо Апача или ssh.
Таким образом если номер порта меньше 1024 то ты знаешь что программа на нем запущена администратором сервера, а не обычным пользователем.
> Это что-то вроде идентификатора соединения в сетевой карте?
Нет, это на уровне ОС, у нее есть список какой порт какой программой открыт и соответственно кому надо передавать пришедшие на этот порт данные. Сетевая карта работает на более низком уровне и просто передает ОС пришедшие пакеты не особо в них разбираясь.
> Таким образом, при работе по ICMP протоколу получается программки даже не открывают соединение с узлом(я так понял, имеется ввиду сетевая карта), у серверочка (как его зовут?) только запрашивается служебная информация: есть ли возможность создать соединение (открыть порт), или нет.
Это при UDP/TCP так. Программа-сервер открывает порт для приема соединений либо программа-клиент просит ОС установить соединение с данными Ip/портом.
В ICMP портов нет и понять какой программе адресован пакет невозможно. Потому под линуксом программа ping использует права администратора, чтобы заставить ОС отдавать ей все пришедшие ICMP-пакеты (без прав админа это сделать нельзя разумеется). Если ты запустишь несколько ping одновременно, они не путаются, так как добавляют в пакеты какие-то свои номера, но это не порт.
Порт идентифицирует программу, не соединение. Соединение идентифицирует 4 числа: IP отправителя/получаетля, порт отправителя/получателя. Таким образом, один порт может использоваться для множества соединений. Например веб-сервер может принимать одновременно сотни соединений на один порт 80 при условии что они приходят от разных IP/портов.
То есть у веб-сервера который слушает порт 80, обычно есть много сокетов (сокет это что-то вроде идентификатора соединения на уровне ОС):
— «слушающий сокет» на порт 80, через который он получает от ОС новые сокеты при подсоединении клиентов к этому порту
— сокеты установленных соединений с клиентами
(это уже особенности того как работает ОС)
> приходят не обязательно в том порядке, что их отправили,
Да, потому что пакеты могут идти разными путями, а также маршрутизатор может по каким-то причинам пересылать их в другом порядке.
> UPD уже позволяет отправить какие-то данные на указанный порт указанного узла (сет.карты), где эти данные уже разбиваются на маленькие пакеты и скармливаются IP протоколу.
У сетевой карты нет портов, порт это просто число по которому ОС идентифицирует программу. У сетевого интерфейса есть только IP адрес и он отправляет/принимает все подряд.
> А когда соединение разрывается? Как происходит этот процесс?
В TCP соединение закрывать может передающая сторона, причем закрывает она этим канал только в одну сторону, на передачу. К примеру, клиент, послав запрос может сразу закрыть канал от клиента к серверу, но оставить открытым канал в обратную сторону (а каждое соединение, как ты помнишь двунаправленное).
Если закрыть канал в обе стороны, очевидно, соединение считается полностью закрытым.
Закрытие делается отправкой специального TCP-пакета с флагом FIN. Он значит «я закончил передавать данные». Получив такой пакет, другая сторона отправляет пакет с флагами FIN + ACK, то есть подтверждает закрытие одного из направлений передачи данных.
Также, есть сброс соединения. Он делается пакетом RST. Он обозначает либо отказ устанавливать соединение, либо если послан после установки, обозначает разрыв соединения. ОС шлет пакеты RST в случае если:
— пришел пакет с попыткой установить соединение на несуществующий порт, на котором никто не слушает (также можно настроить ОС чтобы она ничего не отправляла в ответ, для защиты от сканирования портов)
— программа, которая открыла порт, упала/завершилась. В этом слуае ОС закрывает все открытые ей соединения, посылая пакеты RST
Вот есть длинная, но с графиками, статья про виды пакетов TCP:
http://www.soslan.ru/tcp/tcp18.html
http://www.opennet.ru/docs/RUS/tcpip/#c4_tcp
Кстати, есть программы которые позволяют перрехватывать проходящие через сетевую карту пакеты. Например кроссплатформенный и бесплатный wireshark (с графическим интерфейсом). Можешь поставить его и попробовать, только закрой лишние программы а то будет трудно разобраться. В нем будут видны все свойства пакетов, флаги, порядок установки и разрыва соединения.
Также, команда netstat -abn покажет все открытые соединения и слушающие порты. попробуй ее запустить.
> Устанавливается TCP-соединение с example.com. Приходит полностью html или другой контент, который нам вернул php
Тот кто отправляет данные, закрывает канал на передачу. То есть клиент посылает запрос, закрывает передачу (и сервер это знает так как получил пакет FIN). Сервер посылает ответ, закрывает передачу и соединение считается завершенным так как закрыто в обе стороны.
Именно благодаря закрытию канала при отправке например POST запроса севрер знает когда собственно запрос закончился и можно начинать его обрабатывать. Ведь в HTTP по умоланию нет никакого признака конца данных.
Это по умолчанию, а с Keep-alive конечно канал сразу не закрывается.
> Так вот, если первый запрос завершился 200 OK, то соединение продолжает некоторое время висеть открытым, или как?
По умолчанию закрывается, но клиент и сервер могут договориться не закрывать его с помощью заговков Keep-Alive/Connection. Если будешь смотреть заголвоки на вкладке Network в отладчике, то обрати на них внимание.
> Это слишком сложно, и я не знаю тех языков, на которых подобное пишется (си, я подозреваю).
На PHP есть функции для работы с сокетами: http://php.net/manual/ru/sockets.examples.php
Также, можно открыть соединение через врапперы tcp и udp: http://php.net/manual/ru/function.stream-socket-client.php
Это действительно сложно на первый взгяд, но я думаю написать простые TCP -клиент и сервер пересылающие сообщения, не сложно.
мануалы действительно используют код на СИ. Но если ты понимаешь принцип ты легко перепишешь его на PHP:
http://masandilov.ru/network/guide_to_network_programming
Ну подумай, в общем, я думаю, если писать потихоньку то это не так сложно. Зато ты гораздо лучше будешь понимать что происходит при передаче данных в сети. К тому же в случае с TCP ты можешь установить netcat и она может использоваться как клиент/сервер для тестирования, так как умеет и принимать и устанавливать соединения.
nc -v -l -p 1000 — открыть порт 1000 на прием соединений
nc -v localhost 1000 — соединиться с портом 1000 на своем компьютере
Сделай это в 2 терминалах и получишь мини-чат.
> время установки соединения (ну или эмуляции этого соединения, мы же с портом не коннектимся),
Это время между отправкой и полуением пакета. в ICMP нет соединений, можно только слать пакеты, как в UDP.
> и какой-то ttl.
ttl это поле которое уменьшается на 1 при проходе пакета через маршрутизатор. при достижении нуля пакет уничтожается и отправителю отправляется ICMP-уведомление. Это сделано чтобы при неправильной маршрутизации пакет не ходил по сети вечно.
> ну пик1. Что мне с ним дальше делать?
Ну ты научился пользоваться пингом и узнал что пакеты проходят от тебя до сервера яндекса без проблем.
> Чего он мне гугл только с пятой попытки нашел?
Узлы сети соединены не напрямую, а через маршрутизаторы (которые тоже являются узлами и имеют IP адреса). Traceroute посылает пакеты с возрастающим ttl (которые умрут пройдя несклоько шагов), и выводит тебе пришедшие уведомления об их уничтожении. Таким образом ты видишь каким путем шел пакет к цели.
traceroute позвоялет видеть каким путем идет пакет и обнаруживать проблемы неправильной конфигурации сети.
Там где зведочки, ответа не пришло. Это значит администратор маршрутизатора отключил отправку ICMP уведомлений.
> Говорит 400 bad request
ты неправильно набрал запрос. Проверь пробелы, переводы строк, не перепутано ли что.
> Это слишком сложно, и я не знаю тех языков, на которых подобное пишется (си, я подозреваю).
На PHP есть функции для работы с сокетами: http://php.net/manual/ru/sockets.examples.php
Также, можно открыть соединение через врапперы tcp и udp: http://php.net/manual/ru/function.stream-socket-client.php
Это действительно сложно на первый взгяд, но я думаю написать простые TCP -клиент и сервер пересылающие сообщения, не сложно.
мануалы действительно используют код на СИ. Но если ты понимаешь принцип ты легко перепишешь его на PHP:
http://masandilov.ru/network/guide_to_network_programming
Ну подумай, в общем, я думаю, если писать потихоньку то это не так сложно. Зато ты гораздо лучше будешь понимать что происходит при передаче данных в сети. К тому же в случае с TCP ты можешь установить netcat и она может использоваться как клиент/сервер для тестирования, так как умеет и принимать и устанавливать соединения.
nc -v -l -p 1000 — открыть порт 1000 на прием соединений
nc -v localhost 1000 — соединиться с портом 1000 на своем компьютере
Сделай это в 2 терминалах и получишь мини-чат.
> время установки соединения (ну или эмуляции этого соединения, мы же с портом не коннектимся),
Это время между отправкой и полуением пакета. в ICMP нет соединений, можно только слать пакеты, как в UDP.
> и какой-то ttl.
ttl это поле которое уменьшается на 1 при проходе пакета через маршрутизатор. при достижении нуля пакет уничтожается и отправителю отправляется ICMP-уведомление. Это сделано чтобы при неправильной маршрутизации пакет не ходил по сети вечно.
> ну пик1. Что мне с ним дальше делать?
Ну ты научился пользоваться пингом и узнал что пакеты проходят от тебя до сервера яндекса без проблем.
> Чего он мне гугл только с пятой попытки нашел?
Узлы сети соединены не напрямую, а через маршрутизаторы (которые тоже являются узлами и имеют IP адреса). Traceroute посылает пакеты с возрастающим ttl (которые умрут пройдя несклоько шагов), и выводит тебе пришедшие уведомления об их уничтожении. Таким образом ты видишь каким путем шел пакет к цели.
traceroute позвоялет видеть каким путем идет пакет и обнаруживать проблемы неправильной конфигурации сети.
Там где зведочки, ответа не пришло. Это значит администратор маршрутизатора отключил отправку ICMP уведомлений.
> Говорит 400 bad request
ты неправильно набрал запрос. Проверь пробелы, переводы строк, не перепутано ли что.
Вся проблема в том, что такие полезные посты уходят в никуда. Запилил бы ты рубрику вопрос — ответ, я бы подписался на рсс. Аж обидно, что харкач не знает своих героев.
Это у тебя значит в одно ухо влетело, из другого вылетело.
А я все запоминаю, что он мне отвечает.
В никуда уходят, охуел штоле сука.
Тебе ничто не мешает сохранять его пасты, например.
И можешь тоже задавать вопросы в треде, видишь как он возбуждается от этого.
>Это у тебя значит в одно ухо влетело, из другого вылетело.
Сыранул и не вчитался. Я говорю, что знания должны накапливаться, а не убывать. Я вот написал пост и всё. Спустя 10 тредов мой ответ съест лангольер. Жаль время человека.
И дошел до картинки: https://d262ilb51hltx0.cloudfront.net/max/990/1*NZUhr1jZdBK5YLZogMZgow.png . Она наглядно показывает уровень современного фронтенд"специалиста". Начнем с того что сам бекбон, упоминаемый в посте, построен на классах, только более костыльно и неявно (там по моему есть функция extend или как-то так для наследования). Слово class просто позволяет сделать это наследование более прозрачным.
Ну и далее он пишет «DI ... which of course coupled all those modules to DI container». Это не DI, а service locator в таком случае. Фронтенд-"специалисты" не разобрались в паттернах, набыдлокодили код, а виновато слово class из ES6.Нет, виноваты вы, потому что не разбираетесь в программировании.
Ну и далее сам пост про то что сложно менять new на фабрику, напоминает какой-то бред. Если автор кода использует new, это значит что он хочет создать новый объект. Нет никакой причины заменять это на вызов фабрики (реальная причина, если мы посмотрим на код автора и продолжения поста, то, что ему почему-то нравится создавать объекты через Object.create, а не через new).
В общем, человек явно любитель делать не как все, придумывать какие-то свои велосипеды, и возмущается что ему мешают это делать.
>>510693
Лучше сразу return чтобы читать было проще
>>510701
Я схоронил пасту в текстовый файлик.
что за фаербол?
почему на локалке все норм работает, а на хосте вылезает такое:
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Вот интересно, пхп формат перестал на хосте работать.
$sql_query = "SELECT user_id, user_search_pref, user_photo, user_birthday, user_country_city_name FROM `".PREFIX."_users` WHERE user_search_pref LIKE '%".$query."%' AND user_delet = '0' AND user_ban = '0' ORDER by `user_photo` DESC, `user_country_city_name` DESC LIMIT 0, ".$limit_sql;
$sql_query = "SELECT id, photo, title, add_date, owner_user_id FROM `".PREFIX."_videos` WHERE title LIKE '%".$query."%' AND privacy = 1 ORDER by `views` DESC LIMIT 0, ".$limit_sql;
$sql_query = "SELECT id, title, photo, traf, adres FROM `".PREFIX."_communities` WHERE title LIKE '%".$query."%' AND del = '0' AND ban = '0' ORDER by `traf` DESC, `photo` DESC LIMIT 0, ".$limit_sql;
так оно у меня уже все установлено переустановлено, я просто в душе не ебу, где этот майсокл лежит и как его удалить, в хампе в пакете он есть уже.
Нет
Снеси хамп и поставь руками.
Ирина Астахова, учебник по сикуэль или как-то так называется. 100 страниц подобностей и практических задач.
http://flibusta.net/a/23040
Мразь ёбаная, никогда не отвечай «посмотрю». Ты только что сыранул на советчика.
А проблема в чем?
И на чистом JS встречал. Просто почти все используют jQuery, а там AJAX запрос сделать намного проще и быстрее, чем на JS.
http://myrusakov.ru/php-osnovy.html
делаю вроде как всё правильно, даже посмотрел на ютубе видосы как делают, точно так же. почему у них норм, а у меня нет?
Потому что у тебя прописаны юниксовые пути на винде. А еще установлен openserver. В него вшит вирус, вызывающий рак яичек.
>Ну подумай, в общем, я думаю, если писать потихоньку то это не так сложно.
Давай чуток попозже. Доделаю хоть файлообменник. Там мне осталась регистрация, древовидные комментарии (мне понравилось решение №4 из твоего урока, где создается колонка path вида '1.1.2.1.......', следовательно мы должны хитро вкладывать элементы и парсить dom).
Твою пасту по задачам на xml сохранил, это следующее на очереди. Авось напишу пару патчей для своего киндла, будет хоть чем похвастаться перед родней. А то они думают, что я в игрушки целыми днями играю (неправда, всего 3-4 часа).
Может потом и возьмусь за эту задачу, мне кажется она будет полезной в плане разруливания всяких сокетных соединений, надо бы хороший такой чат написать. Я уже писал, но там тупо гоняются json-строки, это не дело, надо через сокеты.
>Узлы сети соединены не напрямую, а через маршрутизаторы (которые тоже являются узлами и имеют IP адреса)
О, услышал знакомое слово. Про маршрутизацию я читал у Олифер, мало что понял, но хоть знаю красивые слова типа коммутатор и мультиплексор.
Думаю базового знакомства хватит, я же не сисадмин.
>telnet ya.ru 80
Получил заголовки и страницу. Погоди, а зачем ты мне сказал вбить 1.0 вместо 1.1? nginx все равно ответил по новому протоколу.
inside@HP255:~$ telnet ya.ru 80
Trying 213.180.204.3...
Connected to ya.ru.
Escape character is '^]'.
GET / HTTP/1.0
Host: ya.ru
HTTP/1.1 200 Ok
Server: nginx
Date: Wed, 08 Jul 2015 15:04:59 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 9664
Connection: close
Cache-Control: no-cache,no-store,max-age=0,must-revalidate
Expires: Wed, 08 Jul 2015 15:04:59 GMT
Last-Modified: Wed, 08 Jul 2015 15:04:59 GMT
P3P: policyref="/w3c/p3p.xml", CP="NON DSP ADM DEV PSD IVDo OUR IND STP PHY PRE NAV UNI"
Set-Cookie: yandex_gid=143; Expires=Fri, 07-Aug-2015 15:04:59 GMT; Domain=.ya.ru; Path=/
Set-Cookie: yp=; Expires=Sun, 10-Jul-2005 15:04:59 GMT; Path=/
Set-Cookie: yp=; Expires=Sun, 10-Jul-2005 15:04:59 GMT; Domain=.ya.ru; Path=/
Set-Cookie: yp=1438959899.ygu.1; Expires=Sat, 05-Jul-2025 15:04:59 GMT; Domain=.ya.ru; Path=/
Set-Cookie: S=; Expires=Sun, 10-Jul-2005 15:04:59 GMT; Path=/
Set-Cookie: yandexuid=4296845751436367899; Expires=Sat, 05-Jul-2025 15:04:59 GMT; Domain=.ya.ru; Path=/
X-Frame-Options: DENY
>>510640
>Также, команда netstat -abn
verbose наверное, опции b я не нашел.
Ага, порты закреплены за программами, то есть когда придет какой-то поток на тот или иной порт ОС будет знать, кому отдать эти данные на обработку, я понял.
Ладно, ты меня перегрузил. Давай я пока побалуюсь немного с курлом, а потом доделаю многострадальный файлообменник.
Придумай мне задачи на курл. Я тупой, я не могу зазубривать справочники, дай мне практическое задание.
Что можно сделать курлом? Кроме соединения гетом, хедом и постом, что еще интересного можно сделать? Как скачать сайт курлом, не wgetом? Как загрузить/скачать файлы по ftp на хостинг (если они это позволяют, конечно)?
Придумай еще задания, потому что я смутно понимаю, какие у него возможности, а тупо зазубривать команды, не понимая их смысла не охота.
>Ну подумай, в общем, я думаю, если писать потихоньку то это не так сложно.
Давай чуток попозже. Доделаю хоть файлообменник. Там мне осталась регистрация, древовидные комментарии (мне понравилось решение №4 из твоего урока, где создается колонка path вида '1.1.2.1.......', следовательно мы должны хитро вкладывать элементы и парсить dom).
Твою пасту по задачам на xml сохранил, это следующее на очереди. Авось напишу пару патчей для своего киндла, будет хоть чем похвастаться перед родней. А то они думают, что я в игрушки целыми днями играю (неправда, всего 3-4 часа).
Может потом и возьмусь за эту задачу, мне кажется она будет полезной в плане разруливания всяких сокетных соединений, надо бы хороший такой чат написать. Я уже писал, но там тупо гоняются json-строки, это не дело, надо через сокеты.
>Узлы сети соединены не напрямую, а через маршрутизаторы (которые тоже являются узлами и имеют IP адреса)
О, услышал знакомое слово. Про маршрутизацию я читал у Олифер, мало что понял, но хоть знаю красивые слова типа коммутатор и мультиплексор.
Думаю базового знакомства хватит, я же не сисадмин.
>telnet ya.ru 80
Получил заголовки и страницу. Погоди, а зачем ты мне сказал вбить 1.0 вместо 1.1? nginx все равно ответил по новому протоколу.
inside@HP255:~$ telnet ya.ru 80
Trying 213.180.204.3...
Connected to ya.ru.
Escape character is '^]'.
GET / HTTP/1.0
Host: ya.ru
HTTP/1.1 200 Ok
Server: nginx
Date: Wed, 08 Jul 2015 15:04:59 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 9664
Connection: close
Cache-Control: no-cache,no-store,max-age=0,must-revalidate
Expires: Wed, 08 Jul 2015 15:04:59 GMT
Last-Modified: Wed, 08 Jul 2015 15:04:59 GMT
P3P: policyref="/w3c/p3p.xml", CP="NON DSP ADM DEV PSD IVDo OUR IND STP PHY PRE NAV UNI"
Set-Cookie: yandex_gid=143; Expires=Fri, 07-Aug-2015 15:04:59 GMT; Domain=.ya.ru; Path=/
Set-Cookie: yp=; Expires=Sun, 10-Jul-2005 15:04:59 GMT; Path=/
Set-Cookie: yp=; Expires=Sun, 10-Jul-2005 15:04:59 GMT; Domain=.ya.ru; Path=/
Set-Cookie: yp=1438959899.ygu.1; Expires=Sat, 05-Jul-2025 15:04:59 GMT; Domain=.ya.ru; Path=/
Set-Cookie: S=; Expires=Sun, 10-Jul-2005 15:04:59 GMT; Path=/
Set-Cookie: yandexuid=4296845751436367899; Expires=Sat, 05-Jul-2025 15:04:59 GMT; Domain=.ya.ru; Path=/
X-Frame-Options: DENY
>>510640
>Также, команда netstat -abn
verbose наверное, опции b я не нашел.
Ага, порты закреплены за программами, то есть когда придет какой-то поток на тот или иной порт ОС будет знать, кому отдать эти данные на обработку, я понял.
Ладно, ты меня перегрузил. Давай я пока побалуюсь немного с курлом, а потом доделаю многострадальный файлообменник.
Придумай мне задачи на курл. Я тупой, я не могу зазубривать справочники, дай мне практическое задание.
Что можно сделать курлом? Кроме соединения гетом, хедом и постом, что еще интересного можно сделать? Как скачать сайт курлом, не wgetом? Как загрузить/скачать файлы по ftp на хостинг (если они это позволяют, конечно)?
Придумай еще задания, потому что я смутно понимаю, какие у него возможности, а тупо зазубривать команды, не понимая их смысла не охота.
https://github.com/soulsteel/studentProject
Заранее спасибо за конструктивную критику.
>Все PHP файлы НЕОБХОДИМО заканчивать одной пустой строкой.
Это зачем? Насчет отсутствия закрывающего тега ?> понятно, а зачем пустая строка в конце файла? Чем обусловлено это правило?
Чтобы знать, могу ли я стать полноценным пхп-программистом или забить .
По-моему тебе уже можно ставить диагноз.
Ну серьезно, омеганчики, ну как можно быть такими чмошниками? Из-за вашей неуверенности в себе отрасль переполняется тупым быдлом.
Не далее как сегодня общался с одним, это просто пиздец. Эталонное рыгающее быдло, бухое, тупое, самодовольное. Заучило наизусть часть фреймворка, схоронило себе несколько готовых проектов, и копипастит. Я ему говорю, нахуя ты это тут написал? А он говорит "ну вот в том проекте так написано, значит так надо. тот сайт писал чувак покруче тебя, так что не выйобуйся мне тут".
Черт, я специально выбрал айти, чтобы общаться только с умными культурными людьми, а из-за вашей лузерской позиции скоро буду окружен рыгающими колхозниками.
С омеганом сегодня переписывался: "Ты ведь и сам прекрасно понимаешь и видишь ситуацию. Нужно сделать портфолио. А ты один такой? Посмотри любой фриланс сайт. Там таких сотни... И как с ними состязаться? Как бороться за работу?"
Сказал ему не быть ипохондриком, и что на фрилансе большая часть - некомпетентный сброд, обвинил меня в высокомерии. Блять, да идите вы нахуй, опущенцы.
>айти
>умными культурными людьми
Ты не особо блещешь умом, если на самом деле думал, что большинство "айтишников" - умные культурные люди.
>большая часть - некомпетентный сброд,
Всем похуй абсолютно. Большинство работодателей - обычное быдло, которое считает, что более опытный - значит сделает лучше менее опытного. Быдлом управляет страх.
>Эталонное рыгающее быдло, бухое, тупое, самодовольное.
Такое быдло будет собеседовать тебя при приёме на работу. Гарантирую.
>бороться за работу
Ты выбрал карьеру программистишки. Поздравляю. Ты будешь постоянно терпеть унижения ради того, чтобы в 35 лет сидеть в санном опенспейсе, делать сайты на пэхапэ и пить остывший растворимый кофе.
ПРИШЛО ВРЕМЯ УЧИТЬ НОВЫЙ ФРЕЙМВОРК
ФРЕЙМВОРК САМ НЕ ИЗУЧИТСЯ
ИЗУЧИ ЕГО, ИЗУЧИ ЕГО ЕЩЕ РАЗ
ЗАЧЕМ МНЕ НУЖЕН СВОЙ СТАРТАП, У МЕНЯ НЕТ ВРЕМЕНИ ЧТОБЫ ЕБАТЬСЯ С НИМ
ЛУЧШЕ ЕЩЕ РАЗ ВЫУЧИТЬ ФРЕЙМВОРК
Я ИЗУЧАЮ ФРЕЙМВОРК ПО 3 РАЗА В ДЕНЬ
КАЖДОЕ ИЗУЧЕНИЕ ЗАНИМАЕТ ПЯТЬДЕСЯТ МИНУТ
Я ЖИВУ АКТИВНОЙ И ПОЛНОЦЕННОЙ ЖИЗНЬЮ
Я УСПЕШЕН И ПОЭТОМУ ЦЕЛЫЙ ДЕНЬ ПРОГРАММИРУЮ
А ПОСЛЕ ЭТОГО ИЗУЧАЮ НОВЫЙ ФРЕЙМВОРК
ТУПОЕ БЫДЛО ОДЕРЖИМО ДЕНЬГАМИ А Я СВОБОДНЫЙ ОТ ЗАДРОТСТВА ЧЕЛОВЕК
СКАЧАТЬ КНИГУ ПО НОВОМУ ФРЕЙМВОРКУ БЕCПЛАТНО И БЕЗ РЕГИСТРАЦИИ
ЛУЧШЕ Я ИЗУЧУ ЕЩЕ РАЗ ФРЕЙМВОРК
СТАБИЛЬНОСТЬ НЕ НУЖНА Я НЕ ИЗУЧАЛ ФРЕЙМВОРК НЕДЕЛЮ ПОЙДУ ИЗУЧУ НОВЫЙ ФРЕЙМВОРК
ВСЕ ПРОСТО И ПОНЯТНО ОШИБКА TypeError: Object has no method
ЭТО ЖЕ ОЧЕВИДНО КАК ЕЕ РЕШИТЬ
ПРИШЛО ВРЕМЯ ИЗУЧАТЬ ФРЕЙМВОРК
ККОКОКОКОКОКОКО НОВЫЕ ТЕХНОЛОГИИ ФРЕЙМВОРК ПРОГРАММИРОВАНИЕ КОКОКОКОКОКОКО
> схоронило себе несколько готовых проектов
Пиздец, вот такое быдло мне и выдавало "кококо какое у вас портфолио скромное", скромное, зато мое сука, мне как-то совесть не позволяет затирать теги в чужих проекта и копипастить их пиздец.
Я уже удалил все майсоклы которые нашел, кроме хамовского. не работает (кстати наверное зря из Program files его удалил, один раз он работал лел). Хотя это может еще из-за того, что я в настройках и апаче хост для zend rameworka прописал, хуй пойми короче.
>быдло мне и выдавало
Я однажды кинул быдлу ссылочку на свой гитхаб. Быдло начало втирать мне, что это не я типа проекты писал, а спиздил их. Потому что я не подписываю коммиты своим именем по паспорту, а ПСЕВДОНИМОМ. Быдло тупое поколение вконтакте сука не понимает что такое псевдоним нахуй.
Последнее обвиняет ресурс в неправомерной публикации произведений известного американского писателя Рэя Брэдбери. На сайте, без согласования с правообладателями, были размещены романы «451 градус по Фаренгейту», «Вино из одуванчиков», «Марсианские хроники» и «Золотые яблоки солнца».
>ФРЕЙМВОРК САМ СЕБЯ НЕ ИЗУЧИТ
>ТУПОЕ БЫДЛО ОДЕРЖИМО ДЕНЬГАМИ А Я СВОБОДНЫЙ ОТ ЗАДРОТСТВО ЧЕЛОВЕК
Я тебя пофиксил немного, в соответствии с канонами.
http://www.linux.org.ru/forum/development/2792914#comment-2793120
Интересуют второй и третий абзацы.
>>507767
Посмотрел твой код. Хорошо что ты освоил твиг и доктрину, это радует, но пока много замечаний.
> class FileResource
Странное название. Я встречал FileModel, File (по моему лучший вариант), но FileResource это что-то непривычное.
Ты используешь доктрину. Это хорошо, надеюсь ты уже успел убедиться как это удобно, когда не надо писать руками DataMapper, и тебе предоставляется готовый. Более того, если ты будешь использовать доктрину в сложных проектах (где много таблиц и связей между ними), ты увидишь что она способна сэкономить немало времени. Советую и дальше ее стараться использовать.
Но конечно стоит получше изучить ее особенности. Пока я вижу, что ты научился загружать/сохранять сущности в БД, но это лишь самое начало.
Доктрина это довольно сложная библиотека. Ей надо читать метаданные (аннотации в классе FileResource), ей надо парсить и преобразовывать DQL-запросы. Это все требует кеширования, иначе твой код при каждом вызове скрипта будет тратить на это время. В мануале к доктрине это явно написано: http://doctrine-orm.readthedocs.org/en/latest/reference/improving-performance.html#metadata-and-query-caches
> it is strongly discouraged to use Doctrine without a Metadata and Query cache (preferably with APC or Memcache as the cache driver).
Кеширование задается в настройках, и у тебя есть возможность задать какой именно хранилище используется. Для доктрины, мне кажется, хорошо подходит APC, так как это локальный кеш, который использует shared memory (шареную память? на жаргоне ее так называют) и потому работает быстро (но у него есть и недостатки: он недоступен из командной строки, так как память приналежит пользователю, под которым запущен Апач, он локальный по отношению к серверу, но в данном случае это нам и нужно).
Если кеш APC не доступен, можно использовать кеш на файлах. Он наименее эффективен, но для локалхоста, где у нас один пользователь, его возможностей хватит. Зато он не требует ничего устанавливать.
Memcache на мой взгляд для кеширования метаданных наименее выгоден. Он требует установки и доступ к нему идет не напрямую. а через сетевое соединение. Заметь, что он может быть хорош для других задач.
Если открыть исходники доктрины, мы увидим что при выключенном devMode и не указанном кеше, она сама пытается подобрать драйвер:
http://www.doctrine-project.org/api/orm/2.2/source-class-Doctrine.ORM.Tools.Setup.html#163
Мне это не нравится и кажется что это неправильный подход. Ну к примеру, то, что у тебя установлено расширение memcache еще не значит что на том же компьютере запущен сервер memcache.
Потому не полагайся на доктрину, а напиши свой код, который проверяет наличие кеша apc и задействует либо его либо файлы. И выучи команду очистки кеша, разумеется, доктрина не всегда может понять что он устарел при изменениях кода.
Также, доктрине нужна папка для прокси-классов. Прокси-классы это классы-наследники сущностей (вроде FileResource) которые доктрина использует при ленивой загрузке. В общем, та, что она берет по умолчанию, наверно подойдет, но тебе надо знать команду для ее очистки.
Настройки соединения с базой из bootstrap.php хорошо бы вынести в файл-конфиг вида
$dbname = ...;
$user = ....;
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L9
Обычно конструктор только инициализирует объект. Я думаю, лучше тут конструктор не делать, а для ресайза сделать метод resize.
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L26
> strtolower(strrchr($file, '.'));
Не стоит использовать strtolower так как она корежит нелатинские буквы в utf-8.
Определять тип картинки лучше не по расширению, а по типу который вернет например getimagesize().
Опции надо делать константами, а не строками. И в твоем случае список опций запутанный и я не понимаю, зачем их там много и чем они различаются. Мне кажется, это неудачный способ и лучше параметры ресайза задавать как-то по-другому. Ну например, задавать max-height и max-width. Или хотя бы сделать комментарии, как каждый режим работает.
Код определения размеров слишком большой, надо его как-то объединить, потому что там явно многое повторяется.
Зачем нужен exact, я не понимаю. По моему он приводит к нарушению пропорций изображения.
Маленькие картинки не должны увеличиваться. Размеры надо округлять, так как при делении может получиться нечелое число.
> if (imagetypes() & IMG_JPG) {
> imagejpeg($this->imageResized, $savePath, $imageQuality);
Тут при отстутсвии поддердки JPG ты просто молча выходишь из функции как ни в чем не бывало. Это неправильно, фактически картинка не создана а мы делаем вид что все в порядке.
Аналогично с default. Ошибки не должны умалчиваться.
Также, посмотри на свойства этого класса, некторые из них мне кажется можно заменить на обычные переменные и явно передавать между функциями.
> $invertScaleQuality = 9 - $scaleQuality;
Это странный код так как PNG это формат без потерь и его качество не зависит от этого значения. Это значение просто определяет время которое упаковщик потратит на поиск оптимального способа сжатия.
Для MediaInfo надо сделать нормальный методы сохранения/распаковки из JSON, а то ты возвращаешь из getMediaInfo просто массив без методов (так как StdClass это и есть фактически массив только без функций для работы с ним, и его не стоит вообще никогда использовать поэтому). При желании можно даже добавить новый тип в doctrine, чтобы она сама его запаковывала/распаковывала при загрузке и сохранеии, как опсиано тут:
http://doctrine-orm.readthedocs.org/en/latest/cookbook/custom-mapping-types.html
http://doctrine-orm.readthedocs.org/en/latest/cookbook/advanced-field-value-conversion-using-custom-mapping-types.html
Я думаю, стоит сделать тип который позволяет указать класс в который надо мапить данные:
@ORM\Column(type="json", class="MediaInfo")
Такой тип позволит в будущем сохранять в базу и объекты других классов. Также, ты можешь замапить MediaInfo на отдельную таблицу или добавить колонки в files, но это не так интересно.
Я впрочем, изучил код класса Type в доктрине, и у него нет доступа к аннотациям. Так что так сделать не получится, придется делать так:
@ORM\Column(type="mediaInfoType")
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L27
Эту простыню надо разбить на функции или методы.
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L27
> $file = $entityManager->find('Uppu3\Resource\FileResource', $id);
Что если такого файла нет в базе?
> echo $app->render
echo не нужен
>if (in_array($file->getExtension(), $pictures)){
> } elseif (in_array($file->getExtension(), $video)) {
По моему ты сделал неправиьно. Шаблон для просмотра файла должен быть один, а вот уже в нем стоит if/elseif для разных типов.
> header("Content-Disposition: attachment; filename=".$file->getName());
В заголовках можно использовать только латинницу (точнее ASCII), потому нельзя использовать filename для задания имени файла. Для задания имени файла надо делать URL, который на него заканчивается.
> $name = "upload/".$id."-".$file->getName()."-txt";
это (и все аналогичные места) нужно вынести в функцию
> } else {
> echo "Not found";
Неправильно. страница ошибки должна отдаваться с кодом 404 (коды состояния: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2_%D1%81%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D1%8F_HTTP#404 )
Более того, в СЛим уже встроена функция выдачи такой страницы: http://docs.slimframework.com/errors/404/
$entityManager лучше предоставлять как синглтон Слима (также, его удобно сокращать до em): http://docs.slimframework.com/di/overview/ через $app->em
> php_value max_execution_time 1000
Очень странная настройка.
> <meta charset="utf8" />
Слеш в одиночных тегах в HTML не нужен, это не XML
Выравниваение кода в шаблонах ужасное, надо делать отступы, иначе твой код тяжело читать.
> <img src="/upload/resize/resize-{{file.name}}">
Ссылка на картинку должна формироваться функцией или методом, а не быть вписана в нескольких местах кода.
> Размер файла:</strong> {{ file.size }} байт
Стоило бы сделать функцию (и прокинуть ее в twig как фильтр) для вывода размера в человекочитаемом виде.
> name="load"
Не стоит называть кнопку и поле с файлом одинаково.
Также, если требуется запускать какие-то команды, надо добавить файл README с описанием как установить проект.
Где дамп базы данных? Я даже установить наверно его не смогу без нее. Или у тебя он создается доктриной? По моему опыту, удобнее все же создавать таблицы и колонки самостоятельно, так как можно точнее указать тип, добавить комментарии итд.
При попытке отправить форму с невыбранным файлом надо выдавать ошибку.
> https://github.com/V3N0m21/Uppu3/blob/master/app/templates/layout.html#L6
Путь к CSS неправильный. Надо делать не относительный путь, а путь относительно корня сайта, в Слиме есть функция для его получения: http://docs.slimframework.com/request/paths/
Если чо-то непонятно, задавай вопросы.
>>507767
Посмотрел твой код. Хорошо что ты освоил твиг и доктрину, это радует, но пока много замечаний.
> class FileResource
Странное название. Я встречал FileModel, File (по моему лучший вариант), но FileResource это что-то непривычное.
Ты используешь доктрину. Это хорошо, надеюсь ты уже успел убедиться как это удобно, когда не надо писать руками DataMapper, и тебе предоставляется готовый. Более того, если ты будешь использовать доктрину в сложных проектах (где много таблиц и связей между ними), ты увидишь что она способна сэкономить немало времени. Советую и дальше ее стараться использовать.
Но конечно стоит получше изучить ее особенности. Пока я вижу, что ты научился загружать/сохранять сущности в БД, но это лишь самое начало.
Доктрина это довольно сложная библиотека. Ей надо читать метаданные (аннотации в классе FileResource), ей надо парсить и преобразовывать DQL-запросы. Это все требует кеширования, иначе твой код при каждом вызове скрипта будет тратить на это время. В мануале к доктрине это явно написано: http://doctrine-orm.readthedocs.org/en/latest/reference/improving-performance.html#metadata-and-query-caches
> it is strongly discouraged to use Doctrine without a Metadata and Query cache (preferably with APC or Memcache as the cache driver).
Кеширование задается в настройках, и у тебя есть возможность задать какой именно хранилище используется. Для доктрины, мне кажется, хорошо подходит APC, так как это локальный кеш, который использует shared memory (шареную память? на жаргоне ее так называют) и потому работает быстро (но у него есть и недостатки: он недоступен из командной строки, так как память приналежит пользователю, под которым запущен Апач, он локальный по отношению к серверу, но в данном случае это нам и нужно).
Если кеш APC не доступен, можно использовать кеш на файлах. Он наименее эффективен, но для локалхоста, где у нас один пользователь, его возможностей хватит. Зато он не требует ничего устанавливать.
Memcache на мой взгляд для кеширования метаданных наименее выгоден. Он требует установки и доступ к нему идет не напрямую. а через сетевое соединение. Заметь, что он может быть хорош для других задач.
Если открыть исходники доктрины, мы увидим что при выключенном devMode и не указанном кеше, она сама пытается подобрать драйвер:
http://www.doctrine-project.org/api/orm/2.2/source-class-Doctrine.ORM.Tools.Setup.html#163
Мне это не нравится и кажется что это неправильный подход. Ну к примеру, то, что у тебя установлено расширение memcache еще не значит что на том же компьютере запущен сервер memcache.
Потому не полагайся на доктрину, а напиши свой код, который проверяет наличие кеша apc и задействует либо его либо файлы. И выучи команду очистки кеша, разумеется, доктрина не всегда может понять что он устарел при изменениях кода.
Также, доктрине нужна папка для прокси-классов. Прокси-классы это классы-наследники сущностей (вроде FileResource) которые доктрина использует при ленивой загрузке. В общем, та, что она берет по умолчанию, наверно подойдет, но тебе надо знать команду для ее очистки.
Настройки соединения с базой из bootstrap.php хорошо бы вынести в файл-конфиг вида
$dbname = ...;
$user = ....;
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L9
Обычно конструктор только инициализирует объект. Я думаю, лучше тут конструктор не делать, а для ресайза сделать метод resize.
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L26
> strtolower(strrchr($file, '.'));
Не стоит использовать strtolower так как она корежит нелатинские буквы в utf-8.
Определять тип картинки лучше не по расширению, а по типу который вернет например getimagesize().
Опции надо делать константами, а не строками. И в твоем случае список опций запутанный и я не понимаю, зачем их там много и чем они различаются. Мне кажется, это неудачный способ и лучше параметры ресайза задавать как-то по-другому. Ну например, задавать max-height и max-width. Или хотя бы сделать комментарии, как каждый режим работает.
Код определения размеров слишком большой, надо его как-то объединить, потому что там явно многое повторяется.
Зачем нужен exact, я не понимаю. По моему он приводит к нарушению пропорций изображения.
Маленькие картинки не должны увеличиваться. Размеры надо округлять, так как при делении может получиться нечелое число.
> if (imagetypes() & IMG_JPG) {
> imagejpeg($this->imageResized, $savePath, $imageQuality);
Тут при отстутсвии поддердки JPG ты просто молча выходишь из функции как ни в чем не бывало. Это неправильно, фактически картинка не создана а мы делаем вид что все в порядке.
Аналогично с default. Ошибки не должны умалчиваться.
Также, посмотри на свойства этого класса, некторые из них мне кажется можно заменить на обычные переменные и явно передавать между функциями.
> $invertScaleQuality = 9 - $scaleQuality;
Это странный код так как PNG это формат без потерь и его качество не зависит от этого значения. Это значение просто определяет время которое упаковщик потратит на поиск оптимального способа сжатия.
Для MediaInfo надо сделать нормальный методы сохранения/распаковки из JSON, а то ты возвращаешь из getMediaInfo просто массив без методов (так как StdClass это и есть фактически массив только без функций для работы с ним, и его не стоит вообще никогда использовать поэтому). При желании можно даже добавить новый тип в doctrine, чтобы она сама его запаковывала/распаковывала при загрузке и сохранеии, как опсиано тут:
http://doctrine-orm.readthedocs.org/en/latest/cookbook/custom-mapping-types.html
http://doctrine-orm.readthedocs.org/en/latest/cookbook/advanced-field-value-conversion-using-custom-mapping-types.html
Я думаю, стоит сделать тип который позволяет указать класс в который надо мапить данные:
@ORM\Column(type="json", class="MediaInfo")
Такой тип позволит в будущем сохранять в базу и объекты других классов. Также, ты можешь замапить MediaInfo на отдельную таблицу или добавить колонки в files, но это не так интересно.
Я впрочем, изучил код класса Type в доктрине, и у него нет доступа к аннотациям. Так что так сделать не получится, придется делать так:
@ORM\Column(type="mediaInfoType")
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L27
Эту простыню надо разбить на функции или методы.
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L27
> $file = $entityManager->find('Uppu3\Resource\FileResource', $id);
Что если такого файла нет в базе?
> echo $app->render
echo не нужен
>if (in_array($file->getExtension(), $pictures)){
> } elseif (in_array($file->getExtension(), $video)) {
По моему ты сделал неправиьно. Шаблон для просмотра файла должен быть один, а вот уже в нем стоит if/elseif для разных типов.
> header("Content-Disposition: attachment; filename=".$file->getName());
В заголовках можно использовать только латинницу (точнее ASCII), потому нельзя использовать filename для задания имени файла. Для задания имени файла надо делать URL, который на него заканчивается.
> $name = "upload/".$id."-".$file->getName()."-txt";
это (и все аналогичные места) нужно вынести в функцию
> } else {
> echo "Not found";
Неправильно. страница ошибки должна отдаваться с кодом 404 (коды состояния: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2_%D1%81%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D1%8F_HTTP#404 )
Более того, в СЛим уже встроена функция выдачи такой страницы: http://docs.slimframework.com/errors/404/
$entityManager лучше предоставлять как синглтон Слима (также, его удобно сокращать до em): http://docs.slimframework.com/di/overview/ через $app->em
> php_value max_execution_time 1000
Очень странная настройка.
> <meta charset="utf8" />
Слеш в одиночных тегах в HTML не нужен, это не XML
Выравниваение кода в шаблонах ужасное, надо делать отступы, иначе твой код тяжело читать.
> <img src="/upload/resize/resize-{{file.name}}">
Ссылка на картинку должна формироваться функцией или методом, а не быть вписана в нескольких местах кода.
> Размер файла:</strong> {{ file.size }} байт
Стоило бы сделать функцию (и прокинуть ее в twig как фильтр) для вывода размера в человекочитаемом виде.
> name="load"
Не стоит называть кнопку и поле с файлом одинаково.
Также, если требуется запускать какие-то команды, надо добавить файл README с описанием как установить проект.
Где дамп базы данных? Я даже установить наверно его не смогу без нее. Или у тебя он создается доктриной? По моему опыту, удобнее все же создавать таблицы и колонки самостоятельно, так как можно точнее указать тип, добавить комментарии итд.
При попытке отправить форму с невыбранным файлом надо выдавать ошибку.
> https://github.com/V3N0m21/Uppu3/blob/master/app/templates/layout.html#L6
Путь к CSS неправильный. Надо делать не относительный путь, а путь относительно корня сайта, в Слиме есть функция для его получения: http://docs.slimframework.com/request/paths/
Если чо-то непонятно, задавай вопросы.
>>508294
> https://github.com/blackberryJam/abiturients/blob/master/abiturients.sql
Убери из дампа CREATE DATABASE, USE так как у пользователя може быть другая база данных с другим именем.
local лучше сделать ENUM или TINYINT, либо преобразовывать в число при выборке.
> UNIQUE KEY `email_token` (`email`,`token`)
Это значит что один email может встречатья несколько раз если с ним идут разные токены. То точно это имел в виду?
> https://github.com/blackberryJam/abiturients/blob/master/app/autoloader.php#L3
А автозагрузчике надо проверять есть ли такой файл. Иначе код вроде
if (class_exists('sadadsa'))
упадет с ошибкой
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/AbiturientService.php#L9
> $mapper = new AbiturientsMapper($GLOBALS['pdo']);
Не, так не годится. Во-первых ты не должен создавать маппер в сервисе (а должен передавать извне), во-вторых не должен использовать GLOBALS.
Лучше сделать так:
$service = new AbiturientService($abiturientMapper, $validator);
Это назвыается Dependency Injection через конструктор. Урок по теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057
Заметь что для контроллеров обычно это не применяют. Обычно контроллер имеет доступ к DI контейнеру и может получить любой сервис из него. Так что, раз уж ты решил нагородить ООП, сделай-ка DI container. Это класс, который создает или (при повторном обращении) возвращает ранее созданные сервисы, он выглядит примерно так:
$mapper = $container->getAbiturientMapper();
$service = $container->getAbiturientService();
Сами сервисы и мапперы не должны ничего про него знать (иначе код будет запутанным и мы получим service locator), а вот контроллер вполне может иметь к нему доступ. Создавать сам контейнер удобно в bootstrap.php.
Как альтернатива, можно создать контейнер с публичными свойствами и в bootstrap прописать в них мапперы и сервисы, тогда к ним можно обращаться как $container->someMapper. Это работает когда сервисов немного.
В общем код вроде new AbiturientsMapper(...); должен быть только в одном месте. Любой сервис должен быть только в одном экземпляре и не должен создаваться по несколько раз (иначе будет путаница, один экземпляр проставил какое-то поле, а ты вызваешь другой экземпляр где у поля другое значение).
Также, тут в принципе можно было встроить валидатор в сервис. Но можно и отдельным классом, почему бы и нет.
> $string = $string . substr($chars, mt_rand(1, $numChars) - 1, 1);
Тут лучше использовать mb функции, хоть тут и латинница, но лучше привыкать использовать их.
> if ($mapper->isTokenReserved($string) == true) {
> return $this->generateToken($length);
Это потенциально бесконечный цикл. Сделай ограничение. например, можно поместить генерацию токена внутрь for с определенным числом попыток.
> setcookie('flashMessage', $id, time() + 600);
для куки надо указывать path, иначе она будет видна не на всех страницах. Почитай про path тут:
http://citforum.ru/internet/html/cookie.shtml (рус)
https://en.wikipedia.org/wiki/HTTP_cookie#Domain_and_Path (англ)
> switch ($id) {
> case '1':
Я бы сделал это число константой с понятным названием. Также, мне кажется функция readMessage должна сама брать его из кук. А то куки ставятся в сервисе, а читаются где-то в другом месте.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/AbiturientsMapper.php#L6
> public function __construct($pdo)
Нужен тайп-хинт, они полезны и улучшают код.
> foreach ($abiturient as $property => $value)
Мне кажется список полей лучше хранить в массиве, так как теоретически у класса могут добавитьяс поля которые не сохраняются в таблицу. И твой код при добавлении таких полей сломается, это плохо. Код не должен ломатья от добавления поля к классу.
> if ($result["COUNT(x)"] == 0) {
Используй алиас: SELECT COUNT() AS cnt
Если ты слабо знаешь SQL, в ОП-посте есть неплохие задачки на него, которые помогут изучить его лучше.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/FrontController.php
> switch ($_SERVER['REQUEST_URI']) {
Если в URL есть параметры, например /?x=1 то этот код не заработает. надо их отрезать из URL.
Также, что выведется если ни одно из условий не срабоатет? Белая страница? Не, сделай-ка страицу 404 с выдачей соответствущего кода HTTP/1.1 404 Not Found
> processTheRequest
Обычно это называют handle()
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/MainPageController.php#L7
> if ($SERVER['REQUEST_METHOD'] == 'GET') {
А что если метод другой? Если это HEAD? Я думаю, этот if лучше вообще убрать.
> foreach ($abiturient as $property => $value) {
> if (isset($values[$property])) {
> $abiturient->$property = trim($values[$property]);
Это опасный код так как пользователь может прописать любые значения в любые поля объекта. В том числе те поля, которые он редактировать не должен иметь возможность. Я думаю, тут должен быть список допустимых полей.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/UserpageController.php#L4
> public function processTheRequest()
Эта функция слишком длинная. Вынеси отдельные действия в отдеьные методы, например: чтение данных из POST, редирект.
> if ($_SERVER['REQUEST_METHOD'] == 'GET') {
> if (array_key_exists('token', $_COOKIE)) {
> $abiturient = $mapper->getByToken($_COOKIE['token']);
Не понимаю почему это делается толбко при GET.
Алсо, проверку на HTTP метод лучше бы вынести в функцию/метод вроде $this->isPost()
> $_SERVER['DOCUMENT_ROOT']
Лучше бы это не использовать (оно не всегда правильно указывает), а путь определять например через _ _ DIR _ _ .
Также, твои контроллеры выглядят какими-то переусложненными. Может стоит сделать базовый контроллер и в него вынести какие-то общие вещи, не знаю.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/UserpageController.php#L51
Это используется? Если да то надо отрефакторить так как вывод сообщений должен быть в шаблоне, а не в контроллере.
> public function validateInput(Abiturient $abiturient)
Надо очищать список ошибок иначе функцию нельзя вызвать 2 раза подряд.
Имена и фамилии могут содержать дефис, пробел, апостроф: О'Генри.
> $birthyear < 1950) {
Я думаю это несправедливо по отношению к 65-летним
> if ($string != 'male' && $string != 'female') {
Это надо сделать константами в классе Абитуриент.
> strtolower(
Она ломает нелатинские символы и лучше ее вообще не использовать.
> (@){1}
Это то же самое что @
> (.){1,40}
Круглые скобки не требуются
> $regexp = '/(.){1,40}(@){1}(.){1,40}/i';
Эта регулярка не привязана к краям строки и пройдет значение 'лол w@w.com asdadad asd asd as'
Также, почему не используешь флаг u в регулярке? Проще всегда его использовать.
> $regexp = '/[0-9]{3}/';
Регулярка не привязана к краям строки
> <meta name="viewport" content="width=device-width, initial-scale=1">
Это зачем?
> https://github.com/blackberryJam/abiturients/blob/master/templates/basicTemplate.html.php#L12
Это надо вынести в отдельный CSS файл
Папки css и fonts лучше вынести из templates, например в папку static/bootstrap. Также, не стоит менять что-то в бустрапе и удалять файлы, так как потом не разберешься что именно поменялось. Бутстрап надо просто распаковать в папку, ничего не меняя. Аналогично стоит поступать со всеми сторонними библитеками.
> <input type="text" placeholder="Пол ('male', 'female')"
Это надо сделать радиокнопками: http://htmlbook.ru/samhtml5/formy
Изучи какие элементы и возможности есть в формах. Обрати внимание, что в HTML5 есть атрибуты для клиентской валидации, то есть браузер будет проверят форму по заданным тобой правилам. Добавь эти атрибуты. Помни также что клиентская валидация не отменяет серверную валидацию на стороне PHP, она лишь служит для удобства пользователя.
>>508294
> https://github.com/blackberryJam/abiturients/blob/master/abiturients.sql
Убери из дампа CREATE DATABASE, USE так как у пользователя може быть другая база данных с другим именем.
local лучше сделать ENUM или TINYINT, либо преобразовывать в число при выборке.
> UNIQUE KEY `email_token` (`email`,`token`)
Это значит что один email может встречатья несколько раз если с ним идут разные токены. То точно это имел в виду?
> https://github.com/blackberryJam/abiturients/blob/master/app/autoloader.php#L3
А автозагрузчике надо проверять есть ли такой файл. Иначе код вроде
if (class_exists('sadadsa'))
упадет с ошибкой
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/AbiturientService.php#L9
> $mapper = new AbiturientsMapper($GLOBALS['pdo']);
Не, так не годится. Во-первых ты не должен создавать маппер в сервисе (а должен передавать извне), во-вторых не должен использовать GLOBALS.
Лучше сделать так:
$service = new AbiturientService($abiturientMapper, $validator);
Это назвыается Dependency Injection через конструктор. Урок по теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057
Заметь что для контроллеров обычно это не применяют. Обычно контроллер имеет доступ к DI контейнеру и может получить любой сервис из него. Так что, раз уж ты решил нагородить ООП, сделай-ка DI container. Это класс, который создает или (при повторном обращении) возвращает ранее созданные сервисы, он выглядит примерно так:
$mapper = $container->getAbiturientMapper();
$service = $container->getAbiturientService();
Сами сервисы и мапперы не должны ничего про него знать (иначе код будет запутанным и мы получим service locator), а вот контроллер вполне может иметь к нему доступ. Создавать сам контейнер удобно в bootstrap.php.
Как альтернатива, можно создать контейнер с публичными свойствами и в bootstrap прописать в них мапперы и сервисы, тогда к ним можно обращаться как $container->someMapper. Это работает когда сервисов немного.
В общем код вроде new AbiturientsMapper(...); должен быть только в одном месте. Любой сервис должен быть только в одном экземпляре и не должен создаваться по несколько раз (иначе будет путаница, один экземпляр проставил какое-то поле, а ты вызваешь другой экземпляр где у поля другое значение).
Также, тут в принципе можно было встроить валидатор в сервис. Но можно и отдельным классом, почему бы и нет.
> $string = $string . substr($chars, mt_rand(1, $numChars) - 1, 1);
Тут лучше использовать mb функции, хоть тут и латинница, но лучше привыкать использовать их.
> if ($mapper->isTokenReserved($string) == true) {
> return $this->generateToken($length);
Это потенциально бесконечный цикл. Сделай ограничение. например, можно поместить генерацию токена внутрь for с определенным числом попыток.
> setcookie('flashMessage', $id, time() + 600);
для куки надо указывать path, иначе она будет видна не на всех страницах. Почитай про path тут:
http://citforum.ru/internet/html/cookie.shtml (рус)
https://en.wikipedia.org/wiki/HTTP_cookie#Domain_and_Path (англ)
> switch ($id) {
> case '1':
Я бы сделал это число константой с понятным названием. Также, мне кажется функция readMessage должна сама брать его из кук. А то куки ставятся в сервисе, а читаются где-то в другом месте.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/AbiturientsMapper.php#L6
> public function __construct($pdo)
Нужен тайп-хинт, они полезны и улучшают код.
> foreach ($abiturient as $property => $value)
Мне кажется список полей лучше хранить в массиве, так как теоретически у класса могут добавитьяс поля которые не сохраняются в таблицу. И твой код при добавлении таких полей сломается, это плохо. Код не должен ломатья от добавления поля к классу.
> if ($result["COUNT(x)"] == 0) {
Используй алиас: SELECT COUNT() AS cnt
Если ты слабо знаешь SQL, в ОП-посте есть неплохие задачки на него, которые помогут изучить его лучше.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/FrontController.php
> switch ($_SERVER['REQUEST_URI']) {
Если в URL есть параметры, например /?x=1 то этот код не заработает. надо их отрезать из URL.
Также, что выведется если ни одно из условий не срабоатет? Белая страница? Не, сделай-ка страицу 404 с выдачей соответствущего кода HTTP/1.1 404 Not Found
> processTheRequest
Обычно это называют handle()
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/MainPageController.php#L7
> if ($SERVER['REQUEST_METHOD'] == 'GET') {
А что если метод другой? Если это HEAD? Я думаю, этот if лучше вообще убрать.
> foreach ($abiturient as $property => $value) {
> if (isset($values[$property])) {
> $abiturient->$property = trim($values[$property]);
Это опасный код так как пользователь может прописать любые значения в любые поля объекта. В том числе те поля, которые он редактировать не должен иметь возможность. Я думаю, тут должен быть список допустимых полей.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/UserpageController.php#L4
> public function processTheRequest()
Эта функция слишком длинная. Вынеси отдельные действия в отдеьные методы, например: чтение данных из POST, редирект.
> if ($_SERVER['REQUEST_METHOD'] == 'GET') {
> if (array_key_exists('token', $_COOKIE)) {
> $abiturient = $mapper->getByToken($_COOKIE['token']);
Не понимаю почему это делается толбко при GET.
Алсо, проверку на HTTP метод лучше бы вынести в функцию/метод вроде $this->isPost()
> $_SERVER['DOCUMENT_ROOT']
Лучше бы это не использовать (оно не всегда правильно указывает), а путь определять например через _ _ DIR _ _ .
Также, твои контроллеры выглядят какими-то переусложненными. Может стоит сделать базовый контроллер и в него вынести какие-то общие вещи, не знаю.
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/UserpageController.php#L51
Это используется? Если да то надо отрефакторить так как вывод сообщений должен быть в шаблоне, а не в контроллере.
> public function validateInput(Abiturient $abiturient)
Надо очищать список ошибок иначе функцию нельзя вызвать 2 раза подряд.
Имена и фамилии могут содержать дефис, пробел, апостроф: О'Генри.
> $birthyear < 1950) {
Я думаю это несправедливо по отношению к 65-летним
> if ($string != 'male' && $string != 'female') {
Это надо сделать константами в классе Абитуриент.
> strtolower(
Она ломает нелатинские символы и лучше ее вообще не использовать.
> (@){1}
Это то же самое что @
> (.){1,40}
Круглые скобки не требуются
> $regexp = '/(.){1,40}(@){1}(.){1,40}/i';
Эта регулярка не привязана к краям строки и пройдет значение 'лол w@w.com asdadad asd asd as'
Также, почему не используешь флаг u в регулярке? Проще всегда его использовать.
> $regexp = '/[0-9]{3}/';
Регулярка не привязана к краям строки
> <meta name="viewport" content="width=device-width, initial-scale=1">
Это зачем?
> https://github.com/blackberryJam/abiturients/blob/master/templates/basicTemplate.html.php#L12
Это надо вынести в отдельный CSS файл
Папки css и fonts лучше вынести из templates, например в папку static/bootstrap. Также, не стоит менять что-то в бустрапе и удалять файлы, так как потом не разберешься что именно поменялось. Бутстрап надо просто распаковать в папку, ничего не меняя. Аналогично стоит поступать со всеми сторонними библитеками.
> <input type="text" placeholder="Пол ('male', 'female')"
Это надо сделать радиокнопками: http://htmlbook.ru/samhtml5/formy
Изучи какие элементы и возможности есть в формах. Обрати внимание, что в HTML5 есть атрибуты для клиентской валидации, то есть браузер будет проверят форму по заданным тобой правилам. Добавь эти атрибуты. Помни также что клиентская валидация не отменяет серверную валидацию на стороне PHP, она лишь служит для удобства пользователя.
На похапенет иди, там все обстоятельно расписано. Вкратце - магический метод, который вызывается при инициализации объекта класса.
В луковицу не способен?
На кодеакадеми очень базовые знания. Про ООП можно почитать в учебнике из ОП поста, там про него отдельная глава и есть хорошие задания для закрепления.
Нет никакой "природной способности" к логике. Ты можешь ее развить изучая науку Логику. Но ты должен подойти к этому ответственно, т.е. активно рассуждая и рефлексируя над прочитанным материалом, пытаясь уловить/достроить мысль автора. После, если тебе понравится, можно перейти к математической логике, это к слову, тоже интересно.
Если понимаешь, как работают циклы и условия и можешь решить задачу про рост школотронов из учебника ОПа, то все заебись. Потому что есть люди которые не могут понять даже этого. Хуй пойми как они вообще живут. Дальше вопрос наличия времени и усидчивости.
Поясните за фреймворки и энти MVC, насколько они полезны? Я пытался один ковырять, но там вообще какая-то хуета мало похожая на php.
>> https://github.com/blackberryJam/abiturients/blob/master/abiturients.sql
>Убери из дампа CREATE DATABASE, USE так как у пользователя може быть другая база данных с другим именем.
>
>local лучше сделать ENUM или TINYINT, либо преобразовывать в число при выборке.
>
>> UNIQUE KEY `email_token` (`email`,`token`)
>Это значит что один email может встречатья несколько раз если с ним идут разные токены. То точно это имел в виду?
Дамп был старый, уже поменял.
>> switch ($id) {
>> case '1':
>Я бы сделал это число константой с понятным названием. Также, мне кажется функция readMessage должна сама брать его из кук. А то куки ставятся в сервисе, а читаются где-то в другом месте.
Не совсем понял, как и зачем здесь использовать константы. Но теперь код выглядит как-то так:
public function readFlashMessage($cookie)
{
switch ($cookie) {
case 'success':
return 'Данные отправлены.';
break;
}
if (array_key_exists('flashMessage', $_COOKIE)) {
$service = new AbiturientService();
$flashMessage = $service->readFlashMessage($_COOKIE['flashMessage']);
$this->render($abiturient, $errors, $flashMessage);
$service->unsetFlashMessage();
} else {
$this->render($abiturient, $errors);
}
>> https://github.com/blackberryJam/abiturients/blob/master/app/classes/UserpageController.php#L51
>Это используется? Если да то надо отрефакторить так как вывод сообщений должен быть в шаблоне, а не в контроллере.
Да, функция вызывается тут: https://github.com/blackberryJam/abiturients/blob/master/templates/form.html.php#L4
Сначала там был этот самый код, который теперь выведен в отдельную функцию displayAlerts().
С остальными замечаниями буду разбираться, спасибо.
>> https://github.com/blackberryJam/abiturients/blob/master/abiturients.sql
>Убери из дампа CREATE DATABASE, USE так как у пользователя може быть другая база данных с другим именем.
>
>local лучше сделать ENUM или TINYINT, либо преобразовывать в число при выборке.
>
>> UNIQUE KEY `email_token` (`email`,`token`)
>Это значит что один email может встречатья несколько раз если с ним идут разные токены. То точно это имел в виду?
Дамп был старый, уже поменял.
>> switch ($id) {
>> case '1':
>Я бы сделал это число константой с понятным названием. Также, мне кажется функция readMessage должна сама брать его из кук. А то куки ставятся в сервисе, а читаются где-то в другом месте.
Не совсем понял, как и зачем здесь использовать константы. Но теперь код выглядит как-то так:
public function readFlashMessage($cookie)
{
switch ($cookie) {
case 'success':
return 'Данные отправлены.';
break;
}
if (array_key_exists('flashMessage', $_COOKIE)) {
$service = new AbiturientService();
$flashMessage = $service->readFlashMessage($_COOKIE['flashMessage']);
$this->render($abiturient, $errors, $flashMessage);
$service->unsetFlashMessage();
} else {
$this->render($abiturient, $errors);
}
>> https://github.com/blackberryJam/abiturients/blob/master/app/classes/UserpageController.php#L51
>Это используется? Если да то надо отрефакторить так как вывод сообщений должен быть в шаблоне, а не в контроллере.
Да, функция вызывается тут: https://github.com/blackberryJam/abiturients/blob/master/templates/form.html.php#L4
Сначала там был этот самый код, который теперь выведен в отдельную функцию displayAlerts().
С остальными замечаниями буду разбираться, спасибо.
Спасибо, буду разгребать
Дамп SQL не вложил потому что это пока еще совсем черновик, и я хотел уяснить основные моменты и чтоб ты указал мне на критические косяки в моей архитектуре проекта.
Сейчас пройдусь по твоим замечаниям и выложу с дампом
случаенно приклеилась
>учебник из ОП-поста
Ты про тот, где одни задачи и почти нихуя пояснений, типа сам допрёшь, чо как маленький? Нет, спасибо, как-нибудь окольными путями.
Есть гипотеза, что лучше сразу же начинать читать чужой идиоматический код. Буквально нужно читать тысячи проектов. Так ты за год наберёшься опыта больше, чем некоторые за 50-80 лет. Составь список из веб-приложений на пхп. Прочитай их, паралельно пиши свои. 95% чтения кода, 2% написание своего кода, 3% чтение документации и блог постов. Уже через два месяца ты достигнишь уровня сениора, потому что человеческий мозг лучше всего учится на множественных примерах.
Потому что эти задачи учат мышлению, а не применению готовых решений.
>>511507
Так ты станешь макаком-копипастером, не более, если будешь бездумно копировать чужой код.
>Уже через два месяца ты достигнишь уровня сениора
>достигнишь
Школьник, вот давай ты сначала сам "достигнишь", а потом будешь феласофстовавать?
Немного поправил.
Наверное, даже лучше так:
public function readFlashMessage()
{
switch ($_COOKIE['flashMessage']) {
case 'success':
return 'Данные отправлены.';
break;
}
}
if (array_key_exists('flashMessage', $_COOKIE)) {
$service = new AbiturientService();
$flashMessage = $service->readFlashMessage();
$this->render($abiturient, $errors, $flashMessage);
$service->unsetFlashMessage();
} else {
$this->render($abiturient, $errors);
}
Нaпишитe счeтчик количeства мaшин проeзжающих чeрез АЗC, eсли дaны тaкие услoвия(чтобы в любой момeнт времeни он отобрaжал прaвильное количество машин):
с 8:00 - 17:00 - 2800 авто/9 часов (540 минут) = 5 мaшин в минуту
с 17:00 - 22:00 - 2000 авто/4часа (240 мин) = 9 мaшин в минуту
с 22:00 - 01:00 - 200 авто/ 3 часа (180 минут) = 2 мaшины в минуту
с 01:00 - 8:00 - 560 авто/ 8 часов (480 минут) = 1 мaшин в минуту
Через пять минут:
посоны, почему у миня не работает?((( я скопипастил все как в видеоуроке от вована
c:\denwer\../composer/autoload.php
>Вы когда-нибудь слышали про теорему о бесконечных обезьянах? В ней утверждается, что если обезьяна будет беспорядочно нажимать на клавиши клавиатуры бесконечное количество времени, то рано или поздно напечатает заданный текст
О, вот откуда пошел этот мемс про пхп-макак.
> эти задачи учат мышлению
А что делать, если тебя жутко бесит, так, что хочется уебать автору, необходимость разгребать говно, вроде "есть два стула..." языком PHP? Может есть какая-то альтернатива? Лично меня, эти задачи только раздражают, а это не очень способствует обучению.
Ты что сказать-то хотел, залетный?
Форматируй диск С:\, чтобы избавится от вируса.
устраиваюсь фронтэндщиком, зачем-то в тесте дали задание на знание пхп
Есть альтернатива, она называется cms. В вордпрессе нет ничего плохого.
Поймите, быдланчики, что мы (снобы), не из высокомерия или какого-то самоутверждения заставляем вас учить "всю эту хуйню". (Впрочем, есть и такие)
Просто программирование не самая легкая профессия, и малейшая неточность приводит к тому, что код становится непригодным, или крайне неудобным, его приходится чуть ли не с нуля переписывать. Можно плохо класть асфальт, можно плохо чистить канализацию, но в программировании недопустимо кое-как выполнять свою работу. Или отлично, или никак.
Вы лезете сюда, потому что услышали, "шо тут много бабла нахуй". Но эти деньги платятся именно за безукоризненную работу.
За плохие знания никто много не заплатит. В лучшем случае эти деньги можно выбить трудолюбием, выполняя примитивные задания много раз на каком-нибудь фрилансе (что большинство и делает).
>можно плохо класть асфальт, можно плохо чистить канализацию
Низзя.
>в программировании недопустимо кое-как выполнять свою работу
Допустимо, если потребителя всё устраивает.
Странно, тогда в самой вакансии наверное было указано, что нужно знать php?
Если ты его не знаешь, зачем пытаешься туда устроиться?
Работодатель же не из прихоти пишет требования.
Если мы решим тебе эту задачу, завтра перед тобой встанет новая. Изучи основы php, и смело устраивайся в это место.
Задача решается точно так же как и в js ветками условий и преобразованием даты.
Условные конструкции в php
http://php.net/manual/ru/control-structures.if.php
Работа с датой и временем
http://php.net/manual/ru/ref.datetime.php
Какого отсчета? По-моему в задаче нужно написать функцию, которая возвращает либо среднее число автомобилей, проезжающих по статистике через АЗС в тот временной промежуток, к которому эта временная метка относится, либо возвращать количество автомобилей за отрезок времени, если на вход функции подается начало и конец промежутка.
я так понимаю время получается из формы
дата не важна
отсчет времени от 8 утра
т.е. если пользователь введет
17:02 ему должно выдать 2818 машин
>Допустимо, если потребителя всё устраивает.
Поэтому я и упомянул о cms. Там применяются готовые типовые решения (пусть и далеко не идеально реализованные). Никто не будет грузить нестандартными вещами, заставлять решать "головоломки". (Правда головной болью будет, если понадобится что-то обновить, написать плагин, а все перекосится и рухнет)
Все готовенькое, надо только зазубрить, куда тыкать, и где какую последовательность букв прописать в коде, чтобы изменить конфигурацию.
А вот в работе программиста подобные "головоломки" встречаются достаточно часто, и таки придется решать нестандартные задания, но не абстрактные, а вполне себе практичные.
>если потребителя всё устраивает
Погоди, а что значит "пользователя все устраивает"?
Может он не знает, что ты ему впариваешь некачественную работу, и думает что все будет работать долго и надежно.
А оно у него через месяц начнет сыпать ошибками. Ну напишет он в сердцах злобный отзыв о таком "фрелансыре", со вздохом пойдет к следующему вовану, авось хоть здесь повезет.
Лично я буду вполне доволен, если зарплаты программистов рухнут до среднестатистических по стране, тогда в отрасли останутся только люди, которые любят свое дело. Мне не нужны деньги, я хочу гордиться творением своих рук, хочу общаться с людьми, такими же увлеченными и добросовестными.
Ну так и иди работать к единомышленникам, какое тебе дело до остальных людей, которые просто зарабатывают деньги и не такие идейные, как ты? Что за снобизм?
Ну так я здесь и нахожусь, в /pr, а не в /web, /biz, /b или /po.
Эти разделы целиком в вашем распоряжении, уважаемые.
Госпади мне даже твою пасту читать лень, я бы это время лучше потратил на создание формы на пхп для своего блога.
но извини, я собираюсь еще и хостинг покупать, чтобы свои говноподелия тестировать, когда я еще ни копейки даже этим не заработал. у меня такой принцип - пока я чем-то не заработал, я в это не вкладываюсь.
Ну да. Человек обращается к индусам, чтоб работало долго и надёжно, а не из желания сэкономить.
>>510105
>>510112
>>510129
Как обычно PHP дауны кроме PHP ничего не знают, отсюда и рождают такие ебанутые костыли...
Я хоть и сам щас на PHP программирую, но начинал далеко не с него, и опыт большой в разных языках...
Так вот запускать php скрипт (в cli) каждые 13 секунд, лучше всего так, это самый простой и не костыльный способ:
watch -n 13 'php -f time13.php'
Ну и что ты забыл в треде, посвященному языку с самым низким порогом вхождения и следовательно так привлекательного для ненавистных тобою не идейных быдлокодеров? Иди в тред какого-нибудь Haskell или Lisp, там ты точно нас не увидишь.
пфф я решу эту задачу на ангуляре с закрытыми глазами
а hr и дауны вроде тебя считают что без пыхи не обойтись
Вполне себе полноценный язык, со своими недостатками конечно же. Бессмысленно восторгаться одним языком и говорить о несостоятельности другого может только школьник, который не разбирается ни в одном из них.
>Иди
Опять быдлота пытается куда-то меня послать. Надо же.
Но это действует только на слабых и нерешительных людей.
Я еще раз повторяю омежкам: вы видите, какой скам лезет в нашу родную "ботанскую" зону? Будьте решительнее, и увереннее в себе. У вас все получится.
Как вы любите говорить, добра :з, и все такое.
>PHP - язык с самым низким порогом вхождения
Это неправда, мне кажется. Правильно писать на PHP довольно сложно. Сложнее, чем на каком-нибудь питоне.
Самое то между 500 и 800 постом, когда пишут только вопросы по делу и твои полезные ответы.
Вопрос сейчас в том, форсировать уход в бамплимит поддержанием флуда, или оставить все как есть и не обращать внимания?
ну да двачую, пхп чисто денег срубить, а для души и красоты на С кодят.
Задание:
[code]Создание личного кабинета для присвоения статуса и номера принято/в работе/выполненно заявкам созданным с помощью компонента Joomla RS Form. Создание странички с отслеживанием статуса заявки по номеру.[/code]
жду ваши на своём фейкомыльце: koinou@mail.ru
\tRewriteCond %{REQUEST_METHOD} POST
\tRewriteCond %{REQUEST_URI} !/contact.php [NC]
\tRewriteCond %{REMOTE_ADDR} !127.0.0.1
\tRewriteRule .* - [F,L]
Так вот если я сделаю подобный .htaccess файл с именем скрипта в rewriterule и именем жс приложения в rewritecond, даст ли это 100% ную защиту от подделки пост запросов или есть способ её обойти?
Чушь. Начальный уровень быстро прокачивается.
Что касается склада ума, то я уже три раза говорил, что из-за вашей неуверенности в себе ваши места занимают всякие коляны и кабаны. Вот они почему-то ни разу не сомневаются в своих способностях, хотя тупее тебя в два раза. Забавно, да?
ОП, замути им какой-нибудь психологический тренинг, с котиками, смайликами и петушками. Я пытаюсь их подбодрить, а они не понимают и на меня еще агрятся.
А схуяли омежка = умный? Что за бред? Если он портит себе жизнь парясь изо всякой хуйни, то он явно интеллектом не блещет.
прост)
Ой, он же не может собрать объект, получив параметры.
Вот, короче: https://github.com/blackberryJam/abiturients/blob/master/app/classes/Container.php
Теперь он такой.
Интересно, я ещё думаю как пишут скрипты для проверки уникальности текста. Моё представление этого выглядит следующим образом, проверяемый текст разбивается в группы по три слова, причём делается это подобно очереди, то есть одни уходит в группе из трёх слов другой на его место подходит. Потом каждая из этих групп, собранная например в массив делает вызов гугла и проверяет есть ли совпадение например в первых 10 записях (вот тут не знаю как скрипт может проверить выбил ли гугл прямы совпадение, просканировать весь ответ первой десятки и если найти совпадение с текущей группой слов, посчитать что совпадение есть, так? Или есть какие-то АПИ гугла?) и так уже дальше всё выразить в процентах. Или я не так думаю?
Шорткоды https://codex.wordpress.org/ru:Shortcode_API
Что подразумевает заказчик под "номерами", нужно узнать у заказчика. Это часть твоей работы, гордись.
Не нужно решать "ебанутые задачки опа", тут живое общение с людьми. Что Галина Федоровна имела ввиду под "номерами"? Ну вот те цифры на сайте. Молодой человек, вы программист, или нет? За что я вам деньги плачу?
Но в целом задание вполне легкое и адекватное. Чаще тебе придется сталкиваться с переписыванием кривых плагинов, распидорашеными виджетами и т.д.
Внесешь изменение в одну функцию - потянет за собой еще десять, и все перекосится.
А если ты не используешь гит и не знаешь как откатить правку... Энджой йо сиэмэс.
я использую гит. но вообще я уже удалил это письмо, ибо никогда не работал с вордпрессом и в душе не ебу как сверстать кучку сереньких блоков, чтобы потом прикрутить их к вордпрессу. зато на фл.ру как-то удачно и внезапно предложили написать простенькие пхп-функции для тырнет-магазина за норм цену - наконец-то.
идивительные приключения виндузатника
у меня от него WEB-мастер. Проблевался.
https://github.com/V3N0m21/Uppu3
Подправил по замечаниям, но есть парочка вопросов
>При желании можно даже добавить новый тип в doctrine, чтобы она сама его запаковывала/распаковывала при загрузке и сохранеии
Как вот это должно по идее работать? Я должен замапить класс МедиаИнфо как колонку таблицы files?
>В заголовках можно использовать только латинницу (точнее ASCII), потому нельзя использовать filename для задания имени файла.
Но у меня оно почему-то нормально работает с кирилицей. Но если это неправильно, то можешь подсказать что почитать чтоб сделать правильно?
>Для задания имени файла надо делать URL, который на него заканчивается.
Потому что я не совсем понял что это значит
>Путь к CSS неправильный. Надо делать не относительный путь, а путь относительно корня сайта, в Слиме есть функция для его получения: http://docs.slimframework.com/request/paths/
Что-то мне эта слимовская функция не помогла, она возвращает совсем не то что мне нужно
А вы бы откликнулись на эту вакансию, если бы подходили по требованиям?
> Не нужно решать "ебанутые задачки опа"
Что ты бугуртишь? Они действительно ебанутые и не нужны.
Судя по тому, сколько лет она болтается в сети, «мы» не откликаются, причём массово.
1. «Ведущая студия» без пруфов,
2. Слова «ищем целеустремленных веб-разработчиков для работы над серьезными веб-проектами в сильной команде» — это значит, условия как в макДональдс, работа под огнём придирок и обвинений (сей жызненный факт просто надо знать, дизайн-студии давно в таком состоянии, года с 2004 точно)
3. «Разработка и развитие сложных, интересных и известных веб-проектов» — запоминайте. Сложные, высоконагрюзенные ИНТЕРЕСНЫЕ ПРОЕКТЫ, попил, откат, попил, откат, попил, откат, попил, откат, попил, откат, попил, откат...
4. «Знание PHP / HTML / CSS / JS / Jquery» и сразу же «от 40 000» — это за два языка сразу и вёрстку на дивах? До вычета налогов или после? Справа объявление: «Слесарь службы вентиляции и сантехники от 33 000 до 37 000 руб».
5. «Самостоятельность, самокритичность, умение видеть в программировании конечный продукт, а не только процесс написания крутого кода» — самокритичность? Чёбля? Не только работа под огнём придирок и обвинений, но и готовность обвинять себя самого?!! См. хотя бы книги Брайана Трейси, там подробно расписано, а тж. полезно гуглить всё про самооценку, хотя именно этих обезьянок изучает не психология, тут другие науки нужны, счас расскажу какие.
6. «Достойный оклад, квартальные премии по результатам проектов, большие перспективы роста» — ст. 165 УК РФ, «Злоупотребление доверием при отсутствии явных признаков хищения».
7. «Свободный график: 45 часов в неделю (с учетом перерывов на обед и досуг) в любом интервале времени, возможность удаленной работы» — чому не 40 часов в неделю? А случайно не ст. ли это 163 УК РФ «Вымогательство», от 4-х лет сидеть.
8. «Обратите внимание, что на собеседовании мы попросим вас пройти тест на знание PHP. Пожалуйста, не откликайтесь на вакансию, если вы не готовы его пройти по каким-либо причинам» — ст. 330 УК РФ, «Самоуправство», да ещё и нарушение Конституции скорее всего, хотя на неё людишки срать хотели в этой стране. До 7-8 лет в общем.
Если я буду когда-нибудь подбирать название для проекта, я десять раз подумаю. «Кодиксь, Битриксь, Лыбаксь, Пюппиксь» — нет, это не для нас. Наигрались «мы» в эти игры. Хватит уже.
1. «Ведущая студия» без пруфов,
2. Слова «ищем целеустремленных веб-разработчиков для работы над серьезными веб-проектами в сильной команде» — это значит, условия как в макДональдс, работа под огнём придирок и обвинений (сей жызненный факт просто надо знать, дизайн-студии давно в таком состоянии, года с 2004 точно)
3. «Разработка и развитие сложных, интересных и известных веб-проектов» — запоминайте. Сложные, высоконагрюзенные ИНТЕРЕСНЫЕ ПРОЕКТЫ, попил, откат, попил, откат, попил, откат, попил, откат, попил, откат, попил, откат...
4. «Знание PHP / HTML / CSS / JS / Jquery» и сразу же «от 40 000» — это за два языка сразу и вёрстку на дивах? До вычета налогов или после? Справа объявление: «Слесарь службы вентиляции и сантехники от 33 000 до 37 000 руб».
5. «Самостоятельность, самокритичность, умение видеть в программировании конечный продукт, а не только процесс написания крутого кода» — самокритичность? Чёбля? Не только работа под огнём придирок и обвинений, но и готовность обвинять себя самого?!! См. хотя бы книги Брайана Трейси, там подробно расписано, а тж. полезно гуглить всё про самооценку, хотя именно этих обезьянок изучает не психология, тут другие науки нужны, счас расскажу какие.
6. «Достойный оклад, квартальные премии по результатам проектов, большие перспективы роста» — ст. 165 УК РФ, «Злоупотребление доверием при отсутствии явных признаков хищения».
7. «Свободный график: 45 часов в неделю (с учетом перерывов на обед и досуг) в любом интервале времени, возможность удаленной работы» — чому не 40 часов в неделю? А случайно не ст. ли это 163 УК РФ «Вымогательство», от 4-х лет сидеть.
8. «Обратите внимание, что на собеседовании мы попросим вас пройти тест на знание PHP. Пожалуйста, не откликайтесь на вакансию, если вы не готовы его пройти по каким-либо причинам» — ст. 330 УК РФ, «Самоуправство», да ещё и нарушение Конституции скорее всего, хотя на неё людишки срать хотели в этой стране. До 7-8 лет в общем.
Если я буду когда-нибудь подбирать название для проекта, я десять раз подумаю. «Кодиксь, Битриксь, Лыбаксь, Пюппиксь» — нет, это не для нас. Наигрались «мы» в эти игры. Хватит уже.
>это за два языка сразу и вёрстку на дивах?
там наверное знание как у меня - на уровне сделать форму обратной связи и прикрутить готовый плагин.
http://corp.wamba.com/ru/test/test/
эх, еще надо бы задачку опа написать, а потом сделать два прожекта на зенд фреймворке и пожалуй джумоле. как же заебало уже учиться и создаваться сайты в пустоту tbh.
Замечательный тест. На половину вопросов я не особо и знал ответ, так что-то слышал, где-то видел, но наверняка утверждать не берусь и при этом 202 балла. Лол. Хороший программист. Да уж.
Там ещё уровни "отличный программист" и "гуру пхп".
Я ебал такие тесты. С лицом летчика натыкал 155 баллов. Был уверен только в одном вопросе. Хороший программист че.
PHP такой умны и всё равно понимает, что я хотел сказать?
меньше половины же набрал. Там есть результат действительно хороший то приглашают резюме отправить по моему.
Почему после первой строчки у меня работает setcookie(), а если её поменять на вторую, то нет?
Почитай в мануале список каталогов где ищется файл при include. Лучше исплоьзовать абсолбтный путь от корня диска чтоюы не было противоречий:
$file = _ _ DIR _ _ . ....
Потому что кукис отправляются в виде заголовков ответа сервера, им не должен предшествовать вывод, то есть echo или html-теги.
Тебе нужно сначала изучить, что такое куки, и как они реализованы. Изучить http-протокол, чтобы знать, что такое заголовки, и как вообще обменивается данными клиент с сервером.
Это мне известно.
Вопрос в том, почему тогда с первой строчкой всё работает? В обоих случаях кука ставится после вывода хтмл.
Ну я так и хочу сделать, просто заметил такую странность.
тег ?> удали
Не может такого быть. Скинь полностью весь файл, а не эти два инпута, непонятно где ты там что ставишь.
Что значит «не работает»? В чем это проявляется? Как выглядит заголовок Set-Cookie в вкладке Network в отладчике в браузере?
Вот такая ошибка:
[Fri Jul 10 18:08:50.175907 2015] [:error] [pid 1223] [client 127.0.0.1:51109] PHP Warning: Cannot modify header information - headers already sent by (output started at /var/www/site.local/templates/form.html.php:28) in /var/www/site.local/app/classes/AbiturientService.php on line 35, referer: http://site.local/userpage
Причина её ясна -- кука устанавливается после вывода HTML. Мне просто интересно, почему в первом случае это игнорируется.
Ты уверен что ты просто не ошибся? Надо не гадать на кофейной гуще, а сделать повторяемый эксперимент и проверить:
<?php
ini_set('display_errors', 1);
for ($i = 0; $i < 2000; $i++) {
echo $i % 10;
setcookie(...);
}
echo "END";
Выполни этот скрипт и выясни при каком числе символов начинаются ошибки. А я тогда предложу варианты объяснений.
Вот, держи улучшенный скрипт: http://ideone.com/pybybS
Конечно такой скрипт ты должен был написать сам. Инженер должен уметь ставить такие эксперименты.
$i < 3491
Всё работает.
$i < 3492
В браузере:
Веб-страница недоступна
ERR_RESPONSE_HEADERS_TOO_BIG
$i < 10000
В лог приходит аналогичная ошибка. 5903 штуки.
>[Fri Jul 10 18:45:11.131622 2015] [:error] [pid 18621] [client 127.0.0.1:51214] PHP Warning: Cannot modify header information - headers already sent by (output started at /var/www/site.local/test.php:5) in /var/www/site.local/test.php on line 6
И ещё в браузере:
Веб-страница недоступна
ERR_RESPONSE_HEADERS_TOO_BIG
Попробуй браузер получше. У меня хром под Windows перевариает гораздо больше кук.
Также ты можешь заменить установку куки на заголовок поменьше например
header("X:1"); // всего 3 байта :)
Лог:
[Fri Jul 10 18:51:43.915408 2015] [:error] [pid 1222] [client 127.0.0.1:51258] PHP Fatal error: Uncaught exception 'ErrorException' with message 'Cannot modify header information - headers already sent by (output started at /var/www/site.local/test.php:16)' in /var/www/site.local/test.php:17\nStack trace:\n#0 [internal function]: {closure}(2, 'Cannot modify h...', '/var/www/site.l...', 17, Array)\n#1 /var/www/site.local/test.php(17): setcookie('test', '12345', 1436543502)\n#2 {main}\n thrown in /var/www/site.local/test.php on line 17
А в браузере опять "слишком большие заголовки".
Также если ты под линуксом, ты можешь отправится запрос из консоли:
telnet localhost 80 (ENter)
GET /script.php HTTP/1.1 (ENter)
Host: site.local (ENter)
(ENter)
(ENter)
Заодно увидишь страницу глазами браузера.
У меня хром под убунтой. Не экзотика вроде.
Ок, сейчас попробую.
Добавь значение counter в текст ErrrorExceotion:
new ErrorException("Stop, counter = $counter");
Кстати, интересно, я первый раз слушу про ошибку с слишком большими заголовками. Век живи, век учись.
Кстати раз ты под линуксом, ты знаешь про команду
tail -f log
которая следит за логом и постоянно выводит его в консоли? Удобно.
Также есть less +F log которая позвояет переключаться между отслеживанием лога и обычным просмотром.
Вот, что получилось. Как это читать?
anon@anon-desktop:~$ telnet localhost 80
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /var/www/site.local/test.php HTTP/1.1
Host: site.local
HTTP/1.1 200 OK
Date: Fri, 10 Jul 2015 15:58:06 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.11
Content-Length: 0
Content-Type: text/html
Connection closed by foreign host.
anon@anon-desktop:~$
> GET /var/www/site.local/test.php HTTP/1.1
Надо писат тут не путь к файлу, а путь из URL который у тебя в браузере. То есть просто /test.php
Ну сам подумай, откуда браузер знает где ледит файл на сервере? он не знает, потому передает тот путь что в URL, а уже Апач определяет где этот файл на самом деле.
Странно что Апач ответил кодом 200, мне кажется тут должно было быть 404 Not Found, у тебя наверно mod_rewrite используется там в htaccess.
Нет, я только начинаю осваивать. Консоль использую только при работе с git, рестарте апача, некоторых манипуляциях с файлами.
Ну и ещё пара утилит только с консольным интерфейсом.
Сервер отдал тебе в ответ пустую страницу, судя по заголовку Powered-By, это просто запустился PHP скрипт который ничего не вывел (Content-Length: 0). Иначе ты бы увидл то, что он вывел, в низу под заголовками.
>у тебя наверно mod_rewrite используется там в htaccess
Ага.
>>512510
Уже понял. Вот что вывело в итоге:
....тут_много_цифр....0123456789012345 <-----закончилось на 5
Counter=4095
<br />
<b>Fatal error</b>: Uncaught exception 'ErrorException' with message 'Cannot modify header information - headers already sent by (output started at /var/www/site.local/test.php:16)' in /var/www/site.local/test.php:17
Stack trace:
#0 [internal function]: {closure}(2, 'Cannot modify h...', '/var/www/site.l...', 17, Array)
#1 /var/www/site.local/test.php(17): setcookie('test', '12345', 1436544765)
#2 {main}
thrown in <b>/var/www/site.local/test.php</b> on line <b>17</b><br />
Connection closed by foreign host.
Таким образом, получается что если выведено менбше 4096 (включая символ с номером 0) симвлов, то заголвоки посылать можно, а если больше то нельзя? Как это понять?
Для этого надо вспомнить про такую фичу как output buffering. PHP умеет перехватывать данные выводимые через echo и аналогичные команды и складывать их в буфер. А только при заполнении буфера отдавать Апачу (и в браузер соответтвенно). Очевидно пока данные в буфере, и не переданы Апачу, мы все еще можем слать заголовки.
Это делается для оптимизации при выводе данных маленькими кусками (а любой шаблон это и есть вывод данных маленькими кусками), так как послать блок размером 4096 байт быстрее чем послать 4096 блоков по 1 байту.
Буферизацию ты можешь включать и сам, для каких-то своих целей.
http://habrahabr.ru/company/mailru/blog/248573/
http://php.net/manual/ru/outcontrol.examples.basic.php
Осталось только подтвердить или опровергнуть эту версию. Буферизация управляется такими настройками:
http://php.net/manual/ru/outcontrol.configuration.php
Сделай phpinfo() и посмотри чему они равны у тебя.
Разумеется в коде ты не должен полагаться на буферизацию и должен слать заголовки строго до вывода любых данных.
Я кое-что пропустил. Там выше вот что было:
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Set-Cookie: test=12345; expires=Fri, 10-Jul-2015 16:12:45 GMT; Max-Age=-1
Vary: Accept-Encoding
Content-Length: 4600
Content-Type: text/plain; charset=utf-8
Кук поставилось гораздо больше. Собственно, выше одно задание кук, которые вытолкнули мои предыдущие команды.
Ну вот то, что ты видишь это протокол HTTP. Браузер с его помощью запрашивает и получает страницы и файлы с сервера. И как ты видишь, команда cookie всего лишь отправляет заголовок set-Cookie (который потом читает и разбирает браузер).
Спасибо большое тебе.
Очень досаждает подобные неочевидные вещи. Можно было, в принципе и забить, но появляется ДИСКОМФОРТ от не полного понимания того с чем имеешь дело и мыслей вроде "а не поведёт ли оно себя так же в следующий раз".
Хм, интересно, я тоже не знал.
Когда сидел под виндой на сборачке, была железная ошибка при попытке выставить куки после вывода, потому что в вампе видимо output_buffering обнулен.
А на линуксе даже не знал, что по-дефолту php ставится с 4кб буффера.
Только что проверил, у меня тоже 4кб. Я как поставил апт-гетом, так ничего и не менял в конфиге.
>>512534
Могу поделиться кусочком знания, если ты это уже знаешь, то может другим пригодится. Я о такой штуке как BOM.
Сохраняя документ в юникоде, твой редактор добавляет в его начало несколько символов, так называемый byte order mark https://ru.wikipedia.org/wiki/Маркер_последовательности_байтов
Таким образом, если у тебя документ сохранен в юникоде, а output_buffering на нуле, ты будешь удивляться, когда ошибка "cookie already sent" будет появляться даже вот в таком абсолютно корректном коде:
<?php
setcookie('Hello', 'world', time()+3600);
echo 'Where is the error?';
Поэтому специально ради php во многих редакторах вшита возможность сохранять в utf8 БЕЗ BOM. То есть этот необязательный символ удаляется. Всегда сохраняй в utf8 без bom. Если увидишь ошибку "cookie already sent", есть смысл проверить, правильно ли сохранен документ.
Она не ради PHP. Символ BOM придуман, чтобы различат кодировки UTF16-BE и UTF-16LE (точнее, это не разные кодировки, а разные представления юникода). В этих кодировках каждый символ состоит из 2 байт, но порядок разный (да, выбрать единственный порядок разработчики не смогли). В utf-8 такой проблемы нет и BOM не требуется. Но тот же блокнот его вставляет.
В принципе BOM не так и плох, в том плане что помогает определить кодировку, но у него есть и недостатки:
— не все программы его понимают и игнорируют
— при склейке нескоьких файлов c BOM мы полуаем символы BOM в середине, если только программа склеивания не умеет их вырезать
BOM в текстовом редакторе или браузере не проблема, так как это невидимый символ, но программы которые что-то делают на уровне байт, он может сломать.
В общем, тут есть и плюсы и минусы.
>>512572
Да, PHP видит что в начале есть контент и отсылает его в браузер. А так как в HTTP ответе заголовки идут до тела ответа, после этого заголовки уже слать нельзя.
>>512610
Поверяют текст отправляя куски в поисковые системы. Поисковые системы такого использования за бесплатно не любят и блокируют подобные запросы. Советую тебе в это не лезть.
>Поверяют текст отправляя куски в поисковые системы. Поисковые системы такого использования за бесплатно не любят и блокируют подобные запросы. Советую тебе в это не лезть.
Ясно, я лезть не буду, хочется знать технологию, как это делать. Вернее как определить есть совпадение того или иного куска текста в индексе или нет. Просто скопировать текст полученного ответа, то есть всей страницы с выдачей и искать в ней текущие куски текста? Или же есть более лаконичное решение, какие-нибудь специальные функции от гугла?
Если текст есть в гугле очевидно что он не уникален. Попробуй например взять кусок любого текста в кавычках и поискать.
>>512637
Потому что работать стабильно твой скрипт не будет, придется постоянно возиться с проксями, разгадывателями капч и тд.
>>512657
Зависит от хостинга и тарифного плана. Если по правилам можно то наверно все заработает.
MVC? Какие ещё есть? Какие вы используете?
Я что-то почитал про MVC, так его и не понял, как-то слишком сложно. Неужели это удобно?
Чтобы не плодить макаронный код, надо не плодить макаронный код. А именно, выносить дублирующийся/похожий код в отдельные функции, использовать ООП там где уместно, разбивать код на слои, разбивать длинные функции на действия, давать хорошие понятные имена функциям и переменным. Я не могу предложить какой-то мануал на эту тему, но могу предложить изучить фреймворки вроде Yii2 и посмотреть как код написан там.
Также, ты можешь пройти задание про студентов и файлообменник (если знаешь ООП, если нет то сначала задачу на ООП) — они помогут тебе писать более правильный код и освоить MVC.
> Я что-то почитал про MVC, так его и не понял, как-то слишком сложно.
Ты либо читал плохую статью, либо что-то не то. MVC прост и логичен, вся его суть в том что мы разбиваем код, обрабатывающий запрос, на 3 незвисимых части, каждая их котрых занимается своим делом.
Хорошо, что ты задаешь такой вопрос и хочешь понять почему так, а не иначе.
> Какой вообще профит использовать ООП для этой задачи?
Чтобы научиться использовать ООП в MVC приложениях, сделать код читаемее и понятнее. Вот сравни 2 функции:
function doSmth(array $student)
{
...
function doSmth(Student $student)
{
...
Во второй сразу мы знаем какие есть поля и методы у Student. В первой мы ничего не знаем, кроме того что это какой-то массив с какими-то полями, а чтобы понять с какими именно, надо изучать все места где вызывается функция.
Таким образом злоупотребление массивами ведет к получению трудноподдерживаемого кода, и как следствие увелчиению числа ошибок.
Да, в этом приложении кода немного и подход с массивом в принципе может сработать. Но во-первых, в будущем ты будешь писать большие, а не маленькие приложения. Во-вторых, использование объекта вместо массива почти не увеличит код, зато сделает его гораздо качественнее.
Я тебе советую крепко задуматься прежде чем использовать где-то массив. Избавляйся от массивоориентированного мышления.
Такие приложения, как Drupal и Wordpress страдают этим — и в их коде тяжело ориентироваться.
> т.к. всё равно мы реализуем массив $values с введёнными значениями
Не реализуй массив, пиши значения сразу в объект. Зачем там массив?
> а больше ситуаций где может понадобится объект класса студент я не вижу.
В шаблон передать для вывода, в функцию проверки правильности заполнения формы.
Хорошо, что ты задаешь такой вопрос и хочешь понять почему так, а не иначе.
> Какой вообще профит использовать ООП для этой задачи?
Чтобы научиться использовать ООП в MVC приложениях, сделать код читаемее и понятнее. Вот сравни 2 функции:
function doSmth(array $student)
{
...
function doSmth(Student $student)
{
...
Во второй сразу мы знаем какие есть поля и методы у Student. В первой мы ничего не знаем, кроме того что это какой-то массив с какими-то полями, а чтобы понять с какими именно, надо изучать все места где вызывается функция.
Таким образом злоупотребление массивами ведет к получению трудноподдерживаемого кода, и как следствие увелчиению числа ошибок.
Да, в этом приложении кода немного и подход с массивом в принципе может сработать. Но во-первых, в будущем ты будешь писать большие, а не маленькие приложения. Во-вторых, использование объекта вместо массива почти не увеличит код, зато сделает его гораздо качественнее.
Я тебе советую крепко задуматься прежде чем использовать где-то массив. Избавляйся от массивоориентированного мышления.
Такие приложения, как Drupal и Wordpress страдают этим — и в их коде тяжело ориентироваться.
> т.к. всё равно мы реализуем массив $values с введёнными значениями
Не реализуй массив, пиши значения сразу в объект. Зачем там массив?
> а больше ситуаций где может понадобится объект класса студент я не вижу.
В шаблон передать для вывода, в функцию проверки правильности заполнения формы.
Ну и студент тут по моему центральная часть, вокруг которой строится все приложение. Как-то странно было бы не сделать для него класс. Ведь в любую функцию, делаюшую что-либо с ним, мы должны передать модель студента.
Cпасибо за развёрнутый ответ.
$values использовал для записи данных из инпутов по той причине, что код получается гораздо короче, чем если поочерёдно задавать каждое свойство. Но сейчас понял, что можно просто в конструкторе сделать так, чтобы значения брались из инпутов, наверное, сейчас так и сделаю.
Ещё вопрос по поводу ООП, на сколько сильная должна быть абстракция? Где стоит применять ООП, а где можно и обойтись без этого?
> что можно просто в конструкторе сделать так, чтобы значения брались из инпутов,
Это неправильно. Модель не должна ничего знать про форму и массивы вроде GET. Ты размазываешь функционал по всему коду вместо того чтобы каждый занимался своим делом.
Также неудобно когда конструктор принимает на вход массив, так как иногда имы хотим просто создать объект и заполнять его свойства.
Если ты хочешь, ты можешь добавить в студента метод вроде setAttributes, принимающий массив, но не забудь сделать в нем список допустимых для изменения полей.
> по поводу ООП, на сколько сильная должна быть абстракция? Где стоит применять ООП, а где можно и обойтись без этого?
Нужен класс Студент, класс для работы с таблицей студентов (у меня был урок про DataMapper), ну и наверно класс для валидации студента (хотя это можно поместить и в класс работы с БД).
также могут понадобиться какие-то отделные функции которые ни к одному классу не относятся.
Спасибо! Да, про MVC совсем забыл. Обязательно переделаю: понравилось решение с setAttributes
бля, как же меня бесят эти жумала и вордпрессы, пиздец и прочие фреймворки-библиотеки. Знаний программирования и применение пхп кода там никахуя, зато пафоса и ебли со стрелочками фтп клиентами, прикручиванием говна - дохуя.
я не знаю, я еще сам в это говно не вникал, но от вордпресса я в ахуе. (в смысле, что его невозможно вообще подкорректировать).
[code]<?php
error_reporting(-1);
/ Коды для замены букв /
$code = array(
'а'\t=>\t'@',
'ч'\t=>\t'+',
'в'\t=>\t'=',
'у'\t=>\t'&',
'д'\t=>\t'',
'е'\t=>\t'%',
'м'\t=>\t'$',
'р'\t=>\t'-',
'c'\t=>\t'!',
'о'\t=>\t'^',
'и'\t=>\t'#',
'ж' => '('
);
$text = "=@+ &$%-, с^с@+ (#=";
$cipher = strtr($code, $text);
$decode = array_flip ($code);
$code = strtr ($str, $code);
echo "Оригинал: {$text}\nШифровка: {$cipher}\n";
[/code]
[code]<?php
error_reporting(-1);
/ Коды для замены букв /
$code = array(
'а'\t=>\t'@',
'ч'\t=>\t'+',
'в'\t=>\t'=',
'у'\t=>\t'&',
'д'\t=>\t'',
'е'\t=>\t'%',
'м'\t=>\t'$',
'р'\t=>\t'-',
'c'\t=>\t'!',
'о'\t=>\t'^',
'и'\t=>\t'#',
'ж' => '('
);
$text = "=@+ &$%-, с^с@+ (#=";
$cipher = strtr($code, $text);
$decode = array_flip ($code);
$code = strtr ($str, $code);
echo "Оригинал: {$text}\nШифровка: {$cipher}\n";
[/code]
Блять.
На большинстве сайтов почему-то скачивается с непонятным именем, или хеш, или какая-то последовательность цифр.
Почему там так сделано? Может есть какой-то подвох? Например mod_rewrite не на всех серверах работает (на nginx я смотрел, есть ngx_http_rewrite_module), или еще что-то в этом роде? (Подозреваю, что те сайты на cms, и там это удобство тупо не предусмотрели, а не отказались из-за каких-то заумных соображений)
Можно ли и стоит ли писать "кросс-серверный код", чтобы можно было затем перенести с апача на nginx?
Такой еще вопрос: как сделать скачивание архивом нескольких файлов (или даже одного)?
Ссылки типа "скачать .zip", "скачать .rar", "скачать .tar.gz" и т.д.
Подскажите, куда копать в плане работы с архиваторами в php. (Вернее, подскажи, все равно тут кроме опа никто почти по делу не отвечает)
шифровальщик мамкин
Почитай что такое кодировка например cp1251 и utf-8.
Чем однобитовая кодировка отличаеться от двух битной.
Юзай Multibyte String functions
Хотя и проблема в твоем коде в другом если коротко то это пиздец, но для подобных задачь нужно знать что обозначают перечисленные мной выше вещи.
А вообще для шифрования / дешифрования в PHP все есть и городить свои велосипеды не имеет смысла
Аргументы strtr ты передаешь не в том порядке.
А в массиве пары "ключ-значение" в функции strtr определяют "что заменить" (ключ) "на что заменить" (значение).
http://php.net/manual/ru/function.strtr.php
На php.net нечитабельная галиматья
http://php.net/manual/ru/language.oop5.traits.php
Кажется, это набор свойств и методов, которые мы можем затем импортировать в свои классы? (Если да, то почему эти поехавшие так не написали, а зашифровали это простое определение в непонятное?)
Респект, максимально кратко и ясно.
>Понятно что все советуют то-чему они сами обучены
Да.
>более адекватный ответ с чего начать?
Зависит от того, в какой сфере ты собираешься работать.
В веб-разработке, то есть в ремесле создания сайтов, естественно ты должен знать html, css и js (на худой конец jquery). Кроме того, нужно знать язык запросов к базам данных, это sql.
Что касается серверных технологий, то самым популярным на постсоветском пространстве языком по статистике является php. Он не лучше, не хуже других языков, у каждого языка свои преимущества и недостатки.
Кроме php, пишут еще на руби (как по мне он сложнее) и на питоне (менее востребован, чем php, но если ты из Москвы или других крупных городов, то найти работу можно).
На c++ разумеется никто сайты не пишет.
Яву ты похоже путаешь с джаваскриптом. Это совершенно разные языки. Да, джаваскрипт знать нужно.
С чего начать, выбирай сам. Если ты хочешь заниматься веб-разработкой, то php/ruby/python. Геймдев c++. О других языках я не в курсе.
>что нужно знать точно для зарабатывания бабла...
Cms типа wordpress, drupal, bitrix, joomla, opencart и т.д.
Много зарабатывать, работая программистом ты сможешь только если любишь это дело. Потому что знания нужны колоссальные. Если работа не совпадает с твоим хобби, то вряд ли ты дорастешь до этого уровня.
4. К простой форме оформления заказа, которая есть на сайте, добавить расширенную (email, индекс, ФИО, адрес, предпочтительный способ доставки, предпочтительный способ связи с примечанием, что звонки в регионы платные, пожелания и т д), т е необходимые поля добавляет/редактирует/удаляет админ.
5. При заполнении товаров в админке сделать расширенную текстовую форму для возможности, например, писать в столбик, менять цвета, ставить ссылки и т д.
Ну что ты все про хуи да анусы... Сосешь небось? Лижешь?
Все ПХП-шники такие дауны? Тебе же написано, что в синтаксисе ошибка. Вангую, что это из-за доллара перед названием таблицы students.
Мимо-джава-господин
До этого доллара не было, дописал - думал поможет и забыл убрать. Я вижу, что ошибка в синтаксисе поэтому и спрашиваю, ибо делаю по мануалу.
Нет, я неправильно сказал, надо %
иди проспись
Если решил то запости ссылку на ideone для проверки, если не можешь решить то запости ссылку на код и напиши на чем завис. Тут много людей которые уже решили эти задачи и они тебе наверняка подскажут.
Чему у тебя равно $students? Почему ты переменную прямо в запрос подставляешь? Там вообще-то имя таблицы должно быть.
> You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '(name, secname, sex, group, email, mark, year, city)
Это значит в запросе ошибка перед (name ...
Ты там заработался, или захворал опять? Пей чай с малиной и погоняй нубов, нубы сами без тебя далеко не уедут.
>>512836
У меня вопросы накапливаются слишком быстро. Бампну старые и дополню еще одним:
как на файлообменнике сделать проверку хеш-суммы (или как эта шняга называется)?
Чтобы пользователи не могли загрузить одно и то же изображение. (На файлообменнике это пожалуй ни к чему, а вот если делать имиджборду, то по-моему это прекрасное средство от рака. Даунам будет лень постоянно держать под рукой паки)
В таблице с инфой о файлах добавь поле, в которое будешь добавлять хеш загружаемых файлов, который можно получить с помощью функции md5_file. Ну и соответственно при загрузке файла проверяешь хеш загружаемого файла и ищешь файлы с таким хешем в базе.
О, не знал что хеш можно получить не только из строки, но и из файла. Думал хеш-сумма это какая-то неведомая штука, а оказывается обычный md5.
Ясно, спс. Тупой вопрос получился, но уж извините.
По архиваторам додумался зайти на php.net (прогресс), теперь надо только осилить прочитать. Так что снимаю вопрос.
http://php.net/manual/ru/refs.compression.php
С архиватором не все так просто. Создание архива требует времени. Если архив маленький, то можно создать его прямо в скрипте и отдать пользователю. Но если он большой, то нежелательно склеивать файлы в скрипте. Надо использовать очередь задач (вроде gearman), добавлять задачу, показывать пользователю страницу прогресса и периодиески проверять ее статус.
Также нужен крон-скрипт или что-то аналогичное для удаления старых архивов.
>то причина в том, что они очень старые и написаны в то время (лет 40 назад) когда utf-8 и многобайтных кодировок еще не было.
> (лет 40 назад)
> PHP
> 40 лет
Что за еба мануал блять...
Хочеш работать с мульти байтовыми кодировками, юзай mb_ функции
Для тупых школьников капсболдом, как вы любите:
STRTR ПОДДЕРЖИВАЕТ UTF-8, то есть "мульти байтовые" (значение знаешь?) кодировки.
Да, mb_ функции необходимо использовать для замены устаревших аналогов, не работающих с юникодом, например strlen.
Однако функция strtr с юникодом работает, она поддерживает юникод.
> PHP
> 40 лет
> азазаза
Php написан на С (си, есть такой язык, разработанный в начале 70-х), многое от него унаследовал, в частности функции типа strlen.
Подставлял прямо в запрос потому что такой пример есть на хабре (http://habrahabr.ru/post/137664/) - долистать до именных плейсхолдеров. students это название таблица (там по ошибке стоит $),а $student это объект класса Student, имеет 8 полей, всё как обычно.Если кто-то всё таки скажет в чём была трабла, будет круто - надо разобраться, но конкретной необходимости нет, я переделал запрос к базе через mysqli
<?php
error_reporting(-1);
$creditBalance = 40000; / Долг анона перед банком /
$percent = 1.03; / Банк начисляет 3% в месяц от суммы /
$servicePayment = 1000; / А также 1000 рублей в месяц комиссии за обслуживание счета /
$monthlyPayment = 5000; / Анон платит 5000 р в месяц, это все, что ему дает мама на завтраки /
$paymentTotal = 0; / Сколько всего отдал банку анон /
/ Посчитаем расходы 20 раз на 20 месяцев вперед /
for ($month = 1; $month <= 20; $month ++) {
\t$creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
\t$paymentTotal = $paymentTotal + $monthlyPayment;
\techo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
if ($creditBalance < $monthlyPayment) {
$paymentTotal = $paymentTotal+$creditBalance;
echo "{$month} месяц спустя: долг = 0 руб, выплачено всего {$paymentTotal} руб. \n";
break;
}
};
1 месяц спустя: долг = 37200 руб, выплачено всего 5000 руб.
2 месяц спустя: долг = 34316 руб, выплачено всего 10000 руб.
3 месяц спустя: долг = 31345.48 руб, выплачено всего 15000 руб.
4 месяц спустя: долг = 28285.8444 руб, выплачено всего 20000 руб.
5 месяц спустя: долг = 25134.419732 руб, выплачено всего 25000 руб.
6 месяц спустя: долг = 21888.45232396 руб, выплачено всего 30000 руб.
7 месяц спустя: долг = 18545.105893679 руб, выплачено всего 35000 руб.
8 месяц спустя: долг = 15101.459070489 руб, выплачено всего 40000 руб.
9 месяц спустя: долг = 11554.502842604 руб, выплачено всего 45000 руб.
10 месяц спустя: долг = 7901.137927882 руб, выплачено всего 50000 руб.
11 месяц спустя: долг = 4138.1720657184 руб, выплачено всего 55000 руб.
12 месяц спустя: долг = 0 руб, выплачено всего 59138.172065718 руб.
С меня хватит!
<?php
error_reporting(-1);
$creditBalance = 40000; / Долг анона перед банком /
$percent = 1.03; / Банк начисляет 3% в месяц от суммы /
$servicePayment = 1000; / А также 1000 рублей в месяц комиссии за обслуживание счета /
$monthlyPayment = 5000; / Анон платит 5000 р в месяц, это все, что ему дает мама на завтраки /
$paymentTotal = 0; / Сколько всего отдал банку анон /
/ Посчитаем расходы 20 раз на 20 месяцев вперед /
for ($month = 1; $month <= 20; $month ++) {
\t$creditBalance = ( $creditBalance * $percent ) + $servicePayment - $monthlyPayment;
\t$paymentTotal = $paymentTotal + $monthlyPayment;
\techo "{$month} месяц спустя: долг = {$creditBalance} руб, выплачено всего {$paymentTotal} руб. \n";
if ($creditBalance < $monthlyPayment) {
$paymentTotal = $paymentTotal+$creditBalance;
echo "{$month} месяц спустя: долг = 0 руб, выплачено всего {$paymentTotal} руб. \n";
break;
}
};
1 месяц спустя: долг = 37200 руб, выплачено всего 5000 руб.
2 месяц спустя: долг = 34316 руб, выплачено всего 10000 руб.
3 месяц спустя: долг = 31345.48 руб, выплачено всего 15000 руб.
4 месяц спустя: долг = 28285.8444 руб, выплачено всего 20000 руб.
5 месяц спустя: долг = 25134.419732 руб, выплачено всего 25000 руб.
6 месяц спустя: долг = 21888.45232396 руб, выплачено всего 30000 руб.
7 месяц спустя: долг = 18545.105893679 руб, выплачено всего 35000 руб.
8 месяц спустя: долг = 15101.459070489 руб, выплачено всего 40000 руб.
9 месяц спустя: долг = 11554.502842604 руб, выплачено всего 45000 руб.
10 месяц спустя: долг = 7901.137927882 руб, выплачено всего 50000 руб.
11 месяц спустя: долг = 4138.1720657184 руб, выплачено всего 55000 руб.
12 месяц спустя: долг = 0 руб, выплачено всего 59138.172065718 руб.
С меня хватит!
Нормальная обучалка? Я полный даун в програмировании, но неплохо знаю англ. и могу в логику. Прошел первый курс, вроде не сложно.
Тебе надо разобраться в чем ошибка. Иначе какой смысл, получается ты ничего не понял и едиснтвенное что ты умеешь это копипастить код с хабра. Так не пойдет.
> Если кто-то всё таки скажет в чём была трабла,
Очевидно в том что ты подставил несуществующую переменную $students в запрос.
>>513087
надо пройти все курсы, как минимум все бесплатные, а не только введение.
Ну не все сразу же!
> STRTR ПОДДЕРЖИВАЕТ UTF-8
Пруф плиз, не ссылку на какойто еоба гитхаб где пхп уже 40 лет существует, а описание в документации что это так, и дальше будет так (а не просто багофича очередной версии)
> Php написан на С
А Си написал Ричи, которому 70, это значит что PHP 70? Ведь Без Ричи и PHPбы небыло
Она подерживает utf-8 при использовании массива. Если ты указываешь пары для поиска /замены как строки то нет, так как она разбивает их на байты, а в utf-8 символ занимает несколько байт.
Это очевидно если подумать про алгоритм, по которому она работает. Она заменяет валидную последовательность utf-8 символов на другую валидную последовательность, не разрывая их на части.
>Пруф плиз, не ссылку на какойто еоба гитхаб где пхп уже 40 лет существует, а описание в документации что это так, и дальше будет так
Не знаю, есть ли это в документации. Мне лень искать пруф, и лень предлагать в нее дополнения если там этого не написано. Можешь заняться исправлением документации сам, если хочешь.
Првильный ответ 61270. Ты в послежний месяц выплачиваешь сразу 5000 + 4000 и из-за этого получаешь неправильный ответ.
если тебе нужны гарантии что поведение функции не изменится то лучший вариант это никогда не обновлять php.
Пипец ты долбоеб, утверждаеш бред который даже пруфнуть неможеш, специально для тебя болдом напишу
STRTR НЕ ПОДДЕРЖИВАЕТ UTF-8
> Она заменяет валидную последовательность utf-8 символов на другую валидную последовательность, не разрывая их на части.
Она заменяет последовательность байт другой последовательностью байт, а UTF-8 она не поддерживает, то что у тебя правильно заменяться символы в UTF-8 строке, это так, но не вовсех случаях т.к. про UTF-8 она ничего не знает
Раз ты такой умный то для тебя не составит труда продемонстрировать код который, давая функции strtr валидные utf-8 строки получает на выходе невалидную. Чтобы тем самым показать насколько глубоко я заблуждаюсь.
самое интересное, я помню находил позавчера решение этой задачки в одном из тредов, а теперь не могу решить.
Пиздец, где мои 17 лет и нормальные мозги...
Лучше всего стереть код и написать с нуля, так как в учебнике специально дан неправильный код.
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
Ты так ничего и не понял, я лиш пытался опровергнуть твое без основательное заявление про UTF-8, strtr НЕ поддерживает UTF-8, также как и все остальные не mb_ функции, то что из за специфики работы алгоритма strtr она работает с последовательность байт, и поэтому если на вход давать обычные utf-8 символы, то все корректно проходит, но если дать не просто символы а именно последовательность байт которая не совместима с двумя рядом стоящими utf-8 символами, то она их сломает и на выходе будут крякозябры, чегобы не было еслиб функция поддерживала UTF-8 и работала на уровне символов а не байт
> Если ты передаешь на вход невалидные utf-8 последовательности
Пипец ты глупый, strtr на вход получает не utf-8 а последовательность байт (пускай преобразованную из utf-8 символов) и дальше алгоритм работает с байтами и про символы ничего не знает, поэтому если на входе были байты, а функция именно для байт сделана, и эти байты не являются utf-8 символами, но присудствуют по одиночке в utf-8 символах, то в результирующем наборе байт если там должна быть utf-8 строка она будет сломана.
> ты не можешь ожидать валидную последовательность на выходе
Да потому что функция сделана не для работы с символами а для работы с байтами, в одно байтовых кодировках это не имеет разницы а в двух байтовых, выходная строка сломаеться если дать на вход определенную последовательность байт, чего не былобы еслиб функция работала с символами (в установленной кодировке) а не с байтами.
Раз так тупо с понимание этого, то пример напишу чуть позже
с другой стороны вундеркинд растет, респект таким школьникам
я в его возрасте мамок вконтакте ебал, а он уже что-то знает, спорит с авторитетным челом
Ты выводишь одни и те же переменные несколько раз. С чего ты взял, что их содержимое должно поменяться?
Посмотри по той же ссылку, я правильно поправил или через костыли и есть способ проще намного?
$text = "я баран известен всем уже очень давно и это мне только помогает";
$text = explode(" ", $text);
for($i=0; $i<count($text); $i++) {
if($i>1) {
$r[] = $text[$i-1]." ".$text[$i]." ".$text[$i+1];
}
}
for($j=0; $j<count($r); $j++)
{
$res[] = file_get_contents("https://www.google.com.ru/search?q=".$r[$j]);
/Далее лезим в DOM (не помню правдо как) и ищем совпадение с текущим $res[$j]
далее записываем результат, если совпадение есть помечаем строку красным
и также записываем адрес сайта с которым есть совпадение данной\tфразы
далее математически высчитываем процент уникальности. Уже дальше можно занести результат
в базу данных и сохранить на некоторое время по какому-то сгенерированому адресу
на определённое время.
/
}
Он не полный в конце в комментарии я указал что надо делать дальше, поясните ход мыслей правильный? Какие есть подводные камни? Я вижу как минимум один я не знаю как разобраться с тем что к этому скрипту может быть большое количество одновременных запросов, там какие-то заглушки есть кажется не можете подсказать? По поводу того что гугл не любит подобного это я знаю, суть сейчас не в этом. Ещё я читал что у гугла есть API и всё это можно сделать ещё легче, поясните пожалуйста в подробностях если не сложно по поводу всего этого.
$text = "я баран известен всем уже очень давно и это мне только помогает";
$text = explode(" ", $text);
for($i=0; $i<count($text); $i++) {
if($i>1) {
$r[] = $text[$i-1]." ".$text[$i]." ".$text[$i+1];
}
}
for($j=0; $j<count($r); $j++)
{
$res[] = file_get_contents("https://www.google.com.ru/search?q=".$r[$j]);
/Далее лезим в DOM (не помню правдо как) и ищем совпадение с текущим $res[$j]
далее записываем результат, если совпадение есть помечаем строку красным
и также записываем адрес сайта с которым есть совпадение данной\tфразы
далее математически высчитываем процент уникальности. Уже дальше можно занести результат
в базу данных и сохранить на некоторое время по какому-то сгенерированому адресу
на определённое время.
/
}
Он не полный в конце в комментарии я указал что надо делать дальше, поясните ход мыслей правильный? Какие есть подводные камни? Я вижу как минимум один я не знаю как разобраться с тем что к этому скрипту может быть большое количество одновременных запросов, там какие-то заглушки есть кажется не можете подсказать? По поводу того что гугл не любит подобного это я знаю, суть сейчас не в этом. Ещё я читал что у гугла есть API и всё это можно сделать ещё легче, поясните пожалуйста в подробностях если не сложно по поводу всего этого.
Все правильно, count($array) - 1, так и должно быть.
Только смотри, у тебя после \n пробел прилепился. В результате в начале второй и третьей строки получается лишний пробел.
Спасибо
+
http://ideone.com/DL243G
Вот ещё сделал калькулятор, но не способом из методички, ты же не обижаешься, ОП?
Поздно. Выпей йаду.
Не, ну серьезно, сходи в несколько мест и узнай, не убьют же тебя.
На самом деле всем насрать на возраст (ты бы еще про внешность начал), главное чтобы ты справлялся со своей работой.
В худшем случае посадят чистить вордпресс, если туго соображаешь.
А насколько ты готов? В Москве и других крупных городах будут собеседования с тупыми вопросами по теории. Погугли вопросы, которые там задают.
В мухосранях никто даже разговаривать не будет, пока не принесешь пяток качественно выполненных работ в портфолио.
сраницу обнови
Файлообменник, почти копия Ргхоста из задания ОПа будет нормально как для портфолио?
Я не решаю тестовые и домашние задания, и вообще я тут только задачи проверяю. Может впрочем кто-то другой захочет решить твое тестовое задание за тебя.
>>513217
Зависит от компании.
>>513215
Текст с помощью echo выводится только слева направо. Следовательно, надо сначала вывести все первые буквы из каждой строки, затем перейти на вторую строку и вывести вторые буквы из каждой строки, и тд.
>>513188
Про пять работ, точно глупость, какой смысл столько делать за бесплатно? Хватит и одной наверно, или если работ нет, можно предложить сделать тестовое задание.
>>513187
Если в начале идет минус то не работает: http://ideone.com/wkbAi4
При ошибке надо завершать скрипт, нет смысла продолжать выполнять далее.Также желательно писать какой именно символ неправильный.
Вместо предположения что знаки идут нечетными, лучше сделать переменную, которая показывает что было в предыдущий раз.
> break 2;
Таких вещей лучше бы избегать (так как они ломаются при добавлении/вынесении цикла), лучше сделать флаг-переменную наверно или поместить код внутрь функции и использовать return.
Я не решаю тестовые и домашние задания, и вообще я тут только задачи проверяю. Может впрочем кто-то другой захочет решить твое тестовое задание за тебя.
>>513217
Зависит от компании.
>>513215
Текст с помощью echo выводится только слева направо. Следовательно, надо сначала вывести все первые буквы из каждой строки, затем перейти на вторую строку и вывести вторые буквы из каждой строки, и тд.
>>513188
Про пять работ, точно глупость, какой смысл столько делать за бесплатно? Хватит и одной наверно, или если работ нет, можно предложить сделать тестовое задание.
>>513187
Если в начале идет минус то не работает: http://ideone.com/wkbAi4
При ошибке надо завершать скрипт, нет смысла продолжать выполнять далее.Также желательно писать какой именно символ неправильный.
Вместо предположения что знаки идут нечетными, лучше сделать переменную, которая показывает что было в предыдущий раз.
> break 2;
Таких вещей лучше бы избегать (так как они ломаются при добавлении/вынесении цикла), лучше сделать флаг-переменную наверно или поместить код внутрь функции и использовать return.
Тут много ошибок, например не кодируются параметры в URL, никак не обрабатываются сетевые ошибки, непонятно почему текст разбивается на куски по 3 слова, слова могут быть разделены не только проблелом, в общем весь скрипт одна большая ошибка. Из-за этих ошибок он будет выдавать неверные результаты. Ну и ты гарантирвоанно получишь временный бан в гугле (у моего провайдера например общий IP и достаточно одному дурачку запустить такой скрипт чтобы все остались без гугла).
Ну и как я сказал, поисковые системы не одобряют такое использование, ты их ресурсы нагружаешь, а прибыли не приносишь. Мы тоже не одобряем, так как это бессмысленная возня, и твой скрипт будет периодически переставать работать.
Еще есть функция array_rand, смотри мануал, с ней код был бы чуть короче.
>>513141
Ты придираешься к терминам. Если на вход давать валидные utf-8 строки то на выходе тоже получим вылидную строку. Это значит что она корректно обрабатывает строки в этой кодировке.
Так же как например str_repeat: она специально не заточена на работу с utf-8 но корректно с ней работает.
>>513132
> $sentences = array();
> $wordsInSentence = array();
Эта строка не нужна
> if ($key % 2 === 0) {
Это плохой подход, он делает понимание кода сложным (причем в коде комментария к этой строке нет, а вот там, где все и так очевидно, они есть) и опирается на предположение, что предложения и знаки между ними идут в определенном порядке. А что если идет несколько знаков препинания подряд? Лучше обойтись без этого. Например, использовать в регулярке
> $key > 0) ? $preKey = $key - 1: $preKey = 1;
Если ты хочешь написать if то и пиши if а не пытайся его замаскировать и запутать читателя.
?: используется в выражениях, а не как замена if
Само выражение абсолютно непонятное. Непонятно что за манипуляции с индексами, непонятно почему строка для сравнения выглядит как точка с запятой и пробел после нее. Это выглядит хрупким и сломается если чуть поменять код выше.
Так конечно писать не стоит, код должен быть проще и без мин замедленного действия.
В твоем случае можно завести переменную, хранящую предыдущую фразу (или предыдущий зна препинания). И проверять ее регуляркой или ка-кто еще.
> function makeFirstletterLowercase($text) {
А нужна ли эта функция? Не проще всю строку строчными буквами сделать?
> &$value)
Лучше не использовать ссылки так как у них много подводных камней. Также, надо давать нормальные названия переменным, $value бессмысленно и ничего не значит. Очевидно переменная должна называться $sentence.
> \t$regPunct = "/[,:]/u";
>$text = preg_replace($regPunct, '', $text); //у
тут можно не заводить отдельную переменную для регулярки, а вписать ее в функцию.
> $wordsInSentence = preg_split("/(\s)/u", $value, 0,
>PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
Незачем захватывать пробелы. Проще просто указать их в implode.
Еще есть функция array_rand, смотри мануал, с ней код был бы чуть короче.
>>513141
Ты придираешься к терминам. Если на вход давать валидные utf-8 строки то на выходе тоже получим вылидную строку. Это значит что она корректно обрабатывает строки в этой кодировке.
Так же как например str_repeat: она специально не заточена на работу с utf-8 но корректно с ней работает.
>>513132
> $sentences = array();
> $wordsInSentence = array();
Эта строка не нужна
> if ($key % 2 === 0) {
Это плохой подход, он делает понимание кода сложным (причем в коде комментария к этой строке нет, а вот там, где все и так очевидно, они есть) и опирается на предположение, что предложения и знаки между ними идут в определенном порядке. А что если идет несколько знаков препинания подряд? Лучше обойтись без этого. Например, использовать в регулярке
> $key > 0) ? $preKey = $key - 1: $preKey = 1;
Если ты хочешь написать if то и пиши if а не пытайся его замаскировать и запутать читателя.
?: используется в выражениях, а не как замена if
Само выражение абсолютно непонятное. Непонятно что за манипуляции с индексами, непонятно почему строка для сравнения выглядит как точка с запятой и пробел после нее. Это выглядит хрупким и сломается если чуть поменять код выше.
Так конечно писать не стоит, код должен быть проще и без мин замедленного действия.
В твоем случае можно завести переменную, хранящую предыдущую фразу (или предыдущий зна препинания). И проверять ее регуляркой или ка-кто еще.
> function makeFirstletterLowercase($text) {
А нужна ли эта функция? Не проще всю строку строчными буквами сделать?
> &$value)
Лучше не использовать ссылки так как у них много подводных камней. Также, надо давать нормальные названия переменным, $value бессмысленно и ничего не значит. Очевидно переменная должна называться $sentence.
> \t$regPunct = "/[,:]/u";
>$text = preg_replace($regPunct, '', $text); //у
тут можно не заводить отдельную переменную для регулярки, а вписать ее в функцию.
> $wordsInSentence = preg_split("/(\s)/u", $value, 0,
>PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE);
Незачем захватывать пробелы. Проще просто указать их в implode.
В случае со знаками препинания, можно их проверять той же регуляркой вместо условия с индексом.
>>512952
> До этого доллара не было, дописал - думал поможет и забыл убрать. Я вижу, что ошибка в синтаксисе поэтому и спрашиваю, ибо делаю по мануалу.
Это не праивльно, ты должен понимать что ты пишешь а не ставить наугад разные значки.
Доллар обозначает что в строку в это место вставится значение переменной. Чему она у тебя равна? И какая ошибка была без доллара?
И еще, проверь не совпадают ли имена колонок с зарезервированными словами mysql: http://www.mysql.ru/docs/man/Reserved_words.html
Если да то нужны косые кавычки.
>>512922
Лень разбираться. Почитай мануалы к используемой CMS, погугли. Это же твоя работа, ты за нее деньги получаешь, ты ее и делай. Я не знаю кстати даже о какой CMS речь идет.
>>512896
C++ и java очень сложные для новика и требуют много времени. Плюс на собеседованиях по ним могут задавать заковыристые вопросы.
>>512881
Позовляет сделать методы и поля, которые можно добавлять в классы. Мне кажется это скорее вредная штука так как я не могу вспомнить примеров где они бы были правильным решением. я видел несколько раз их использование, это были неправильные случаи так как там правильнее было сделать наследование.
Если у классов много общего, их наверно стоит наследовать и трейты не нужны. Если в классы надо добавить общий функционал, наверно лучше сделать его отдельным объектом и внедрять через конструктор.
Лучше уметь правильно пользоваться обычными возможностями ООП.
>>512891
Плохая аналогия, так как намекает что трейты неплохая вещь, хотя я не могу вспомнить адекватных примеров где они были бы нужны.
>>512846
Твой пост никак не помогает разобраться и потому не нужен тут.
> Чем однобитовая кодировка отличаеться от двух битной.
Ты же сам фигню пишешь, какая еще двухбитная кодировка? Это в которой всего 4 символа что ли?
>>512836
> а большинстве сайтов почему-то скачивается с непонятным именем, или хеш, или какая-то последовательность цифр.
Низкий уровень знания потому что, люди не хотят учиться в нашем треде а хотят учиться по мутным видеокурсам где про это не рассказывают. Конечно, имя должно быть нормальное чтобы пользователь потом не рылся среди кучи непонятных файлов.
> Можно ли и стоит ли писать "кросс-серверный код", чтобы можно было затем перенести с апача на nginx?
Можно но на практике не нужно так как известно под каким сервером будет работать проект, а если очень требуется, можно просто сделать опцию в конфиге или проверять через get_sapi_name().
> Подскажите, куда копать в плане работы с архиваторами в php.
Есть расширения, но их установка под windows може тсодержать подвохи в виде поиска нужных dll.
Также, на крайний случай, можно взять консольную версию архиватора 7zip и вызвыать ее, она поддерживает кучу форматов, но надо разбираться с тем как правильно запускать и контроллировать дочерний процесс, как получать информацию о успехе/неудаче операции, как экранировать передаваемые имена файлов, как логгировать сообщения об ошибках, где гарантия что не получится архив с пропщенными файлами.
В случае со знаками препинания, можно их проверять той же регуляркой вместо условия с индексом.
>>512952
> До этого доллара не было, дописал - думал поможет и забыл убрать. Я вижу, что ошибка в синтаксисе поэтому и спрашиваю, ибо делаю по мануалу.
Это не праивльно, ты должен понимать что ты пишешь а не ставить наугад разные значки.
Доллар обозначает что в строку в это место вставится значение переменной. Чему она у тебя равна? И какая ошибка была без доллара?
И еще, проверь не совпадают ли имена колонок с зарезервированными словами mysql: http://www.mysql.ru/docs/man/Reserved_words.html
Если да то нужны косые кавычки.
>>512922
Лень разбираться. Почитай мануалы к используемой CMS, погугли. Это же твоя работа, ты за нее деньги получаешь, ты ее и делай. Я не знаю кстати даже о какой CMS речь идет.
>>512896
C++ и java очень сложные для новика и требуют много времени. Плюс на собеседованиях по ним могут задавать заковыристые вопросы.
>>512881
Позовляет сделать методы и поля, которые можно добавлять в классы. Мне кажется это скорее вредная штука так как я не могу вспомнить примеров где они бы были правильным решением. я видел несколько раз их использование, это были неправильные случаи так как там правильнее было сделать наследование.
Если у классов много общего, их наверно стоит наследовать и трейты не нужны. Если в классы надо добавить общий функционал, наверно лучше сделать его отдельным объектом и внедрять через конструктор.
Лучше уметь правильно пользоваться обычными возможностями ООП.
>>512891
Плохая аналогия, так как намекает что трейты неплохая вещь, хотя я не могу вспомнить адекватных примеров где они были бы нужны.
>>512846
Твой пост никак не помогает разобраться и потому не нужен тут.
> Чем однобитовая кодировка отличаеться от двух битной.
Ты же сам фигню пишешь, какая еще двухбитная кодировка? Это в которой всего 4 символа что ли?
>>512836
> а большинстве сайтов почему-то скачивается с непонятным именем, или хеш, или какая-то последовательность цифр.
Низкий уровень знания потому что, люди не хотят учиться в нашем треде а хотят учиться по мутным видеокурсам где про это не рассказывают. Конечно, имя должно быть нормальное чтобы пользователь потом не рылся среди кучи непонятных файлов.
> Можно ли и стоит ли писать "кросс-серверный код", чтобы можно было затем перенести с апача на nginx?
Можно но на практике не нужно так как известно под каким сервером будет работать проект, а если очень требуется, можно просто сделать опцию в конфиге или проверять через get_sapi_name().
> Подскажите, куда копать в плане работы с архиваторами в php.
Есть расширения, но их установка под windows може тсодержать подвохи в виде поиска нужных dll.
Также, на крайний случай, можно взять консольную версию архиватора 7zip и вызвыать ее, она поддерживает кучу форматов, но надо разбираться с тем как правильно запускать и контроллировать дочерний процесс, как получать информацию о успехе/неудаче операции, как экранировать передаваемые имена файлов, как логгировать сообщения об ошибках, где гарантия что не получится архив с пропщенными файлами.
<script type="text/javascript">
Cufon.replace("div.font");
Cufon.replace("div.font1");
Cufon.replace("div.brev");
Cufon.replace(".catalog_text");
Cufon.replace(".catalog_text_2");
Cufon.replace(".prnext");
Cufon.replace(".prcatalog_text");
Cufon.replace(".m_fonts");
</script>
Что это блять? ЦМСка какая-то?
Если ты не знаешь, как динамически из админки создавать инпуты, то что ты вообще в вебе делаешь? чисто задачки из ОП-поста решаешь?
Почему? Там же есть API и хуки для плагинов.
>>512758
Мануал по CMS читал для начала?
>>512740
Хороший программист и с ними справится.
>>512562
> Если увидишь ошибку "cookie already sent",
Новые версии PHP пишут строку в которой начался вывод, так что искать долго не придется (если конечно это не невидимый BOM который путает новичков).
>>512539
Это полезный дискомфорт, старайся всегда разбираться если что-то непонятно или нелогично.
>>512254
> Я должен замапить класс МедиаИнфо как колонку таблицы files?
Ну тип в доктрине определяет как данные преобразуются при записи или загрузке из БД. Соответственно твой класс, реализующий этот тип, должен преобразовывать данные между объектом класса MediaInfo и строкой в формате JSON. То есть пара строчек на каждый случай.
После этого помечаешь поле в объекте File этим типом и доктрина сама начинает сохранять/загружать MediaInfo из него в базу.
> Но у меня оно почему-то нормально работает с кирилицей.
Потому что ты не тестировал во всех бразерах, а те что у тебя интерпретируют заголовки как utf-8 хотя не обязаны.
> то можешь подсказать что почитать чтоб сделать правильно?
Древний и 100% способ это сделать чтоыб ссылка на скаичванеи заканчивалась именем файла. В новых браузерах ты также можешь закодировать имя в специальном формате: https://tools.ietf.org/html/rfc5987#section-3.2.2
Мне кажется старый способ работающий везде, пока что лучше. То есть делай ссылку вида
/download/123/название%20файла.jpg
Не забудь кодировать имя файла процентным кодированием (urlencode) при подстановке в ссылку.
> Что-то мне эта слимовская функция не помогла, она возвращает совсем не то что мне нужно
Покажи пример кода.
Почему? Там же есть API и хуки для плагинов.
>>512758
Мануал по CMS читал для начала?
>>512740
Хороший программист и с ними справится.
>>512562
> Если увидишь ошибку "cookie already sent",
Новые версии PHP пишут строку в которой начался вывод, так что искать долго не придется (если конечно это не невидимый BOM который путает новичков).
>>512539
Это полезный дискомфорт, старайся всегда разбираться если что-то непонятно или нелогично.
>>512254
> Я должен замапить класс МедиаИнфо как колонку таблицы files?
Ну тип в доктрине определяет как данные преобразуются при записи или загрузке из БД. Соответственно твой класс, реализующий этот тип, должен преобразовывать данные между объектом класса MediaInfo и строкой в формате JSON. То есть пара строчек на каждый случай.
После этого помечаешь поле в объекте File этим типом и доктрина сама начинает сохранять/загружать MediaInfo из него в базу.
> Но у меня оно почему-то нормально работает с кирилицей.
Потому что ты не тестировал во всех бразерах, а те что у тебя интерпретируют заголовки как utf-8 хотя не обязаны.
> то можешь подсказать что почитать чтоб сделать правильно?
Древний и 100% способ это сделать чтоыб ссылка на скаичванеи заканчивалась именем файла. В новых браузерах ты также можешь закодировать имя в специальном формате: https://tools.ietf.org/html/rfc5987#section-3.2.2
Мне кажется старый способ работающий везде, пока что лучше. То есть делай ссылку вида
/download/123/название%20файла.jpg
Не забудь кодировать имя файла процентным кодированием (urlencode) при подстановке в ссылку.
> Что-то мне эта слимовская функция не помогла, она возвращает совсем не то что мне нужно
Покажи пример кода.
>>512226
Действительно, какой-то клуб 40-летних неудачников получается. Хочу всем напомнить что наш тред посвящен программированию, а нытьем лучше заниматься в других разделах. Сопли тут вам вытирать никто не будет.
>>512226
Насчет SQL, ты смотрел ссылки отсюда: https://gist.github.com/codedokode/10539213
?
Там хороший туториал для начинающих есть.
>>512054
> if (!isset($this->$class)) {
Вот это неправильно. Завязывай с динамиечскими свойствами, объект это не массив чтобы в него их добавлять (а если тебе нужны динамические свойства, используй лучше массив).
Вместо swtch лучше сделать функции вида
public function getValidator()
{
if (!$this->validator) {
$this->validator = new ... ;
}
return $this->validator;
}
Тогда и код будет логичнее и будет сразу видно какие есть методы у класса, и в IDE автодополнение будет работать.
Ты вместо простого и очевидного решения (сделать метод для каждого класа) зачем-то решил усложнить код, сделав процесс создания объекта более сложным и непрямолинейным.
В фреймфорках есть готовые решения для этого, так что думаю в будущем тебе не придется такие контейнеры писать.
> default:
> $this->$class = new $class;
Это неправитльно. Ты готов создавать что угодно никак не проверяя вообще что это за класс.
Ну и как ты наверно успел заметить, контейнеры отравляют код, заставляя передавать его в каждый конструктор. Потому мы используем их только в контроллерах, которые все равно повторно исплоьзовать нельзя.
В фреймворках контейнеры реализуются по-разному. В симфони контейнер настраивается файлом конфигурации, ты в нем описываешь сервисы, какой класс используется, что ему надо передать в конструктор: http://symfony-gu.ru/documentation/ru/html/book/service_container.html
В микрофреймворке Слим ты можешь заполнять контейнер с помощью анонимных функций: http://docs.slimframework.com/di/overview/
В Юи сервисы получаются через объект фреймворка, доступный глобыльно:
$someModel = Yii::app()->model('some');
Ну Юи известен своими велосипедами, что с него взять.
>>512226
Действительно, какой-то клуб 40-летних неудачников получается. Хочу всем напомнить что наш тред посвящен программированию, а нытьем лучше заниматься в других разделах. Сопли тут вам вытирать никто не будет.
>>512226
Насчет SQL, ты смотрел ссылки отсюда: https://gist.github.com/codedokode/10539213
?
Там хороший туториал для начинающих есть.
>>512054
> if (!isset($this->$class)) {
Вот это неправильно. Завязывай с динамиечскими свойствами, объект это не массив чтобы в него их добавлять (а если тебе нужны динамические свойства, используй лучше массив).
Вместо swtch лучше сделать функции вида
public function getValidator()
{
if (!$this->validator) {
$this->validator = new ... ;
}
return $this->validator;
}
Тогда и код будет логичнее и будет сразу видно какие есть методы у класса, и в IDE автодополнение будет работать.
Ты вместо простого и очевидного решения (сделать метод для каждого класа) зачем-то решил усложнить код, сделав процесс создания объекта более сложным и непрямолинейным.
В фреймфорках есть готовые решения для этого, так что думаю в будущем тебе не придется такие контейнеры писать.
> default:
> $this->$class = new $class;
Это неправитльно. Ты готов создавать что угодно никак не проверяя вообще что это за класс.
Ну и как ты наверно успел заметить, контейнеры отравляют код, заставляя передавать его в каждый конструктор. Потому мы используем их только в контроллерах, которые все равно повторно исплоьзовать нельзя.
В фреймворках контейнеры реализуются по-разному. В симфони контейнер настраивается файлом конфигурации, ты в нем описываешь сервисы, какой класс используется, что ему надо передать в конструктор: http://symfony-gu.ru/documentation/ru/html/book/service_container.html
В микрофреймворке Слим ты можешь заполнять контейнер с помощью анонимных функций: http://docs.slimframework.com/di/overview/
В Юи сервисы получаются через объект фреймворка, доступный глобыльно:
$someModel = Yii::app()->model('some');
Ну Юи известен своими велосипедами, что с него взять.
Пользователь полностью контроллирует что происходит на стороне браузера, как ты собрался от него защищаться? Ты можешь только выиграть немного времени, обфусцировав код и добавив какие-нибуь подписи и проверки, но принципиально защититься нельзя.
>>511627
Если эти ссылки не надо менять в админке то проще всего просто прописать их в нужный шаблон HTML-кодом без PHP. Чтобы вывести записи с определенным тегом достаточно кликнуть по нему и посмотреть как выглядит ссылка.
>>511629
Нет ты
>>511597
Зарплаты не рухнут так как их подпитывает западный рынок, а на нем пока даже зарплата уборщика в макдональдсе выше чем у нас. Если конечно ты не знаешь английский. то твоя зарплата вполне может и рухнуть (точнее, рухнет валюта в которой ее платят) в случае ухудшения международных отношений.
>>511544
Я думаю, для обезьяны превратиться в образованного человека займет меньше времени чем напечатать текст.
>>511521
Работа с флеш сообщениями должна быть в отдельных функциях/методах. Никаких таких проверок быть не должно:
> f (array_key_exists('flashMessage', $_COOKIE)) {
Потмоу что ими ты размаывешь логику работы с сообщениями (как они хранятся, под каким ключом, где) по всему коду вместо того чтобы изолировать в классе или функции. Это неправильно.
Также, я не понимаю почему работа с флеш сообщенями помещена в AbiturientService. Их можно использовать для любых объектов, не только абиутриетов, и значит в этом сервисе их не должно быть.
>>511503
Зря, по моему неплохой учебник.
>>511456
абсолютно необходимиы.
>>511452
Не все же должны уметь в программирование. Ты может быть петь или бегать марафоны не умеешь и как-то же живешь с этим.
А понять можно при желании, если изучать все последовательно и задавать вопросы. А не смотреть мутные статьи и видеокурсы.
>>511392
> Если же вы описываете сущность, единственное предназначение которой - сгруппировать данные, то это не объект, это структура, и тут (чаще всего) геттеры и сеттеры не нужны
это не очень дальновидный подход так как завтра тебе понадобится например при записи проверять что знаечние поля находится в диапазоне от 1 до 100. Или при смене одного поля менять и другое. В случае сеттера ты добавишь эту проверку туда. В случае публичного поля тебя ждет проход по всему коду и замена поля на геттер/сеттер. Потому некоторые рекомендуют вообще не использовать публичные поля.
В очень простых случаях, когда ты знаешь что такого не будет, это допустимо. То есть мы уменьшает время написания кода ценой потенциальнх исправлений в будущем (хотя проще наверно макрос в редакторе сдеать для геттеров/сеттеров, вот мой для саблайма: https://gist.github.com/codedokode/cd2f41c8dcf1237fde4b )
Рассуждения про стурктуры дурь, так как в большом приложении рано или поздно необходимость что-то проверять или делать при изменении поля появится, по моему опыту.
Люди которые любят рассуждать что ООП не нужен, как правило в нем не особо хорошо разбираются.
Пользователь полностью контроллирует что происходит на стороне браузера, как ты собрался от него защищаться? Ты можешь только выиграть немного времени, обфусцировав код и добавив какие-нибуь подписи и проверки, но принципиально защититься нельзя.
>>511627
Если эти ссылки не надо менять в админке то проще всего просто прописать их в нужный шаблон HTML-кодом без PHP. Чтобы вывести записи с определенным тегом достаточно кликнуть по нему и посмотреть как выглядит ссылка.
>>511629
Нет ты
>>511597
Зарплаты не рухнут так как их подпитывает западный рынок, а на нем пока даже зарплата уборщика в макдональдсе выше чем у нас. Если конечно ты не знаешь английский. то твоя зарплата вполне может и рухнуть (точнее, рухнет валюта в которой ее платят) в случае ухудшения международных отношений.
>>511544
Я думаю, для обезьяны превратиться в образованного человека займет меньше времени чем напечатать текст.
>>511521
Работа с флеш сообщениями должна быть в отдельных функциях/методах. Никаких таких проверок быть не должно:
> f (array_key_exists('flashMessage', $_COOKIE)) {
Потмоу что ими ты размаывешь логику работы с сообщениями (как они хранятся, под каким ключом, где) по всему коду вместо того чтобы изолировать в классе или функции. Это неправильно.
Также, я не понимаю почему работа с флеш сообщенями помещена в AbiturientService. Их можно использовать для любых объектов, не только абиутриетов, и значит в этом сервисе их не должно быть.
>>511503
Зря, по моему неплохой учебник.
>>511456
абсолютно необходимиы.
>>511452
Не все же должны уметь в программирование. Ты может быть петь или бегать марафоны не умеешь и как-то же живешь с этим.
А понять можно при желании, если изучать все последовательно и задавать вопросы. А не смотреть мутные статьи и видеокурсы.
>>511392
> Если же вы описываете сущность, единственное предназначение которой - сгруппировать данные, то это не объект, это структура, и тут (чаще всего) геттеры и сеттеры не нужны
это не очень дальновидный подход так как завтра тебе понадобится например при записи проверять что знаечние поля находится в диапазоне от 1 до 100. Или при смене одного поля менять и другое. В случае сеттера ты добавишь эту проверку туда. В случае публичного поля тебя ждет проход по всему коду и замена поля на геттер/сеттер. Потому некоторые рекомендуют вообще не использовать публичные поля.
В очень простых случаях, когда ты знаешь что такого не будет, это допустимо. То есть мы уменьшает время написания кода ценой потенциальнх исправлений в будущем (хотя проще наверно макрос в редакторе сдеать для геттеров/сеттеров, вот мой для саблайма: https://gist.github.com/codedokode/cd2f41c8dcf1237fde4b )
Рассуждения про стурктуры дурь, так как в большом приложении рано или поздно необходимость что-то проверять или делать при изменении поля появится, по моему опыту.
Люди которые любят рассуждать что ООП не нужен, как правило в нем не особо хорошо разбираются.
Спасибо, попробую пересмотреть свою реализацию контейнера.
>В фреймфорках есть готовые решения для этого, так что думаю в будущем тебе не придется такие контейнеры писать.
Ну хотелось бы, чтоб фреймворки являлись для меня этими самыми "чОрными ящиками" как можно в более меньшей степени. И не быть потом сильно от них зависимым.
Наш урок про реуглярки прошел?
Есть сайт regex101, на нем можно тестировать регулярки.
Есть маунал PHP, подробный но малопонятный: http://php.net/manual/ru/pcre.pattern.php
Можно задать вопрос в треде.
>>511382
если бы в твоем посте было поменьше слов «быдло», он мог бы выглядеть адекватным. Ну и требования все же устанавливает работодатель, сделаешь свою компанию и будешь сам с соискателями общаться как хочешь.
>>511381
Удалять надо через пуск - настройка - установку/удаление программ. У тебя мог остаться запущенный сервис например.
Зайди в пуск -> services.msc и посмотри нет ли там лишних сервисов mysql. Ну и в установке/удалении программ посмотри.
И поясни что значит «mysql не работает». Это как?
>>511352
Судя по тексту твоего поста ты недалеко ушел от тех кого критикуешь. Читать невозможно.
Вместо того чтобы баттхертить ты бы мог просто устроиться в нормальную компанию и/или развиваться в то время пока ковырятели вордпрессов передвигают очередное меню на 5 пикселей выше.
>>511273
Я видел такое требование и в других программах под линуксом. как я понимаю это для единообразия, чтобы в конце каждой строки стоял \n:
Строка1\n
Строка2\n
PHP будет работать нормально независимо от этого, да и большинство других программ тоже, по моему эта проблема из прошлого. Хотя гит и сегодня предупреждает про отстутсвующую пустую строку в конце файла.
Наш урок про реуглярки прошел?
Есть сайт regex101, на нем можно тестировать регулярки.
Есть маунал PHP, подробный но малопонятный: http://php.net/manual/ru/pcre.pattern.php
Можно задать вопрос в треде.
>>511382
если бы в твоем посте было поменьше слов «быдло», он мог бы выглядеть адекватным. Ну и требования все же устанавливает работодатель, сделаешь свою компанию и будешь сам с соискателями общаться как хочешь.
>>511381
Удалять надо через пуск - настройка - установку/удаление программ. У тебя мог остаться запущенный сервис например.
Зайди в пуск -> services.msc и посмотри нет ли там лишних сервисов mysql. Ну и в установке/удалении программ посмотри.
И поясни что значит «mysql не работает». Это как?
>>511352
Судя по тексту твоего поста ты недалеко ушел от тех кого критикуешь. Читать невозможно.
Вместо того чтобы баттхертить ты бы мог просто устроиться в нормальную компанию и/или развиваться в то время пока ковырятели вордпрессов передвигают очередное меню на 5 пикселей выше.
>>511273
Я видел такое требование и в других программах под линуксом. как я понимаю это для единообразия, чтобы в конце каждой строки стоял \n:
Строка1\n
Строка2\n
PHP будет работать нормально независимо от этого, да и большинство других программ тоже, по моему эта проблема из прошлого. Хотя гит и сегодня предупреждает про отстутсвующую пустую строку в конце файла.
Алсо если бы ты погуглил по словам why end file with empty line ты бы нашел:
http://stackoverflow.com/questions/2287967/why-is-it-recommended-to-have-empty-line-in-the-end-of-file
(тут здравая мысль что в консоли файл лучше выводтся в этом случае и отсылка к POSIX) http://stackoverflow.com/questions/729692/why-should-files-end-with-a-newline
http://unix.stackexchange.com/questions/18743/whats-the-point-in-adding-a-new-line-to-the-end-of-a-file
http://www.reddit.com/r/Python/comments/1zjugg/question_why_does_pep8_recommend_leaving_a_blank/
В общем остылка к тому что в linux принято ставить симвл \n в конце каждой строки включая последнюю.
Не забыть проверить этого анона https://github.com/soulsteel/studentProject
В проекте нет SQL файла где описана структура таблицы.
> if($locality === "local") {
Значения locality и пола надо сделать константами в классе студента:
const LOCALITY_LOCAL = 'local';
Константы принято использовать когда есть несколько вариантов значения. Не использовать их считается плохой практикой так как легче ошиьиться и неочевидно какие значения есть вообще.
Впрочем если ты хоанишь локальность в виде 0\1 то лучше не делать константы а использовать true/false. А для пола — сделать.
validate должна очищать список ошибок в начале работы.
> use PDO;
Это наверно не требуется, можно писать просто \PDO. Но можно и как у тебя.
> $data = [
> "firstName" => $student->getFirstName(),
Надо писать имя плейсхолдера вместе с двоеточием в массиве.
Что еще за поле password? Скопировал не задумываясь?
> public function getStudents($mask, $num, $offset, $direction)
Все вставялемые в запрос значения надо проверят по белому списку для защиты от SQL инхекций.
> " LIMIT " . $offset . ", " . $num;
Тут нужны плейсхолдеры
> LIKE " . "\"%" . $phrase . "%\"";
И тут. Пока у тебя тут SQL инъекция с помощью которой можно легко взломать сайт.
> $recordsNum = $statement->fetch(PDO::FETCH_ASSOC)["recordsNum"];
Исплоьзуй fetchColumn
> $options = array(
> PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
> PDO::MYSQL_ATTR_INIT_COMMAND => 'SET sql_mode=\'STRICT_ALL_TABLES\'',
Это лучше вынести из конфига так как это не надо менять, также второй ключ в массиве затрет первый.
> https://github.com/soulsteel/studentProject/blob/master/app/helpers.php#L21
Тут надо сделать грамотно защиту от XSS в переменной $text. ЧТО если тамкакие-то HTML теги?
Твое нынешнее решение конечно предотвращает XSS:
> html(highlightMatch($student->getFirstName(), $phrase))
но оно же превращает тег <mark> в текст. ты тестировал подсветку?
> require_once "/config.php";
Сомневаюсь что это работает так как это абсолютный путь указывающий в корень диска или ФС.
> <?php if (isset($errors["firstName"])): ?>
> <input type="text" class="form-control" id="inputError2"
> <?php else: ?>
> input type="text" id="inputFirstName"
надо избежать дублирования кода инпута. Попробуй переделать этот if, например засунув в него только отдельные атрибуты и теги.
Аналогично с радиокнопками.
> https://github.com/soulsteel/studentProject/blob/master/templates/navbar.php#L6
Почему по английски?
Почему есть header.php но нет footer.php?
Папку vendor надо добавить в гитигнор и убрать из репозитория.
Ну и я немного побуду граммар наци:
> which contains two pages: main and register
frontpage and registration page
> List of students, currently registered is shown
list of currently registered students is shown (порядок слов)
> In this project a part of web app created, which contains two pages:
The project is a (part of a) web app that consists of two pages
> in the form of table
as a table
Не забыть проверить этого анона https://github.com/soulsteel/studentProject
В проекте нет SQL файла где описана структура таблицы.
> if($locality === "local") {
Значения locality и пола надо сделать константами в классе студента:
const LOCALITY_LOCAL = 'local';
Константы принято использовать когда есть несколько вариантов значения. Не использовать их считается плохой практикой так как легче ошиьиться и неочевидно какие значения есть вообще.
Впрочем если ты хоанишь локальность в виде 0\1 то лучше не делать константы а использовать true/false. А для пола — сделать.
validate должна очищать список ошибок в начале работы.
> use PDO;
Это наверно не требуется, можно писать просто \PDO. Но можно и как у тебя.
> $data = [
> "firstName" => $student->getFirstName(),
Надо писать имя плейсхолдера вместе с двоеточием в массиве.
Что еще за поле password? Скопировал не задумываясь?
> public function getStudents($mask, $num, $offset, $direction)
Все вставялемые в запрос значения надо проверят по белому списку для защиты от SQL инхекций.
> " LIMIT " . $offset . ", " . $num;
Тут нужны плейсхолдеры
> LIKE " . "\"%" . $phrase . "%\"";
И тут. Пока у тебя тут SQL инъекция с помощью которой можно легко взломать сайт.
> $recordsNum = $statement->fetch(PDO::FETCH_ASSOC)["recordsNum"];
Исплоьзуй fetchColumn
> $options = array(
> PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
> PDO::MYSQL_ATTR_INIT_COMMAND => 'SET sql_mode=\'STRICT_ALL_TABLES\'',
Это лучше вынести из конфига так как это не надо менять, также второй ключ в массиве затрет первый.
> https://github.com/soulsteel/studentProject/blob/master/app/helpers.php#L21
Тут надо сделать грамотно защиту от XSS в переменной $text. ЧТО если тамкакие-то HTML теги?
Твое нынешнее решение конечно предотвращает XSS:
> html(highlightMatch($student->getFirstName(), $phrase))
но оно же превращает тег <mark> в текст. ты тестировал подсветку?
> require_once "/config.php";
Сомневаюсь что это работает так как это абсолютный путь указывающий в корень диска или ФС.
> <?php if (isset($errors["firstName"])): ?>
> <input type="text" class="form-control" id="inputError2"
> <?php else: ?>
> input type="text" id="inputFirstName"
надо избежать дублирования кода инпута. Попробуй переделать этот if, например засунув в него только отдельные атрибуты и теги.
Аналогично с радиокнопками.
> https://github.com/soulsteel/studentProject/blob/master/templates/navbar.php#L6
Почему по английски?
Почему есть header.php но нет footer.php?
Папку vendor надо добавить в гитигнор и убрать из репозитория.
Ну и я немного побуду граммар наци:
> which contains two pages: main and register
frontpage and registration page
> List of students, currently registered is shown
list of currently registered students is shown (порядок слов)
> In this project a part of web app created, which contains two pages:
The project is a (part of a) web app that consists of two pages
> in the form of table
as a table
Можно подумать, я хотя бы буду знать, что писать. Вообще да, лучше бы я начал задрачивать ЦМСки и писать их и учить готовые, потому что сайты НЕ ДЛЯ СЕБЯ со всякими шаблонами и редакторами я еще не делал.
Я к тому, что когда начнешь что-то масштабное писать, в итоге у тебя через некоторое время такая же мешанина непонятная выйдет, в которой другому разбираться полгода. ЦМСки для того и созданы, чтобы хоть как-то облегчить задачу вникания в чужой код. Ну и расширять их легче, чем самописный велосипед с костылями.
> Я уже писал, но там тупо гоняются json-строки, это не дело, надо через сокеты.
Веб-сокеты и просто сокеты разные вещи, я имел в виду именно обычные сокеты, то есть TCp-соединения и UDP-пакеты. Вебсокеты поверх них построены и их имеет смысл наверно чут позже изучить (хотя можно и наоборот, они не сложные вроде).
> verbose наверное, опции b я не нашел.
В виндоуз она показывает программу занявшую порт. В линукс это опция
> -p, --program
> Show the PID and name of the program to which each socket belongs.
> Давай я пока побалуюсь немного с курлом
Тогда можешь сделать задачу про определение адреса через яндекс-API. Если не хочешь заморочиться с XMl, то геокодер позволяет отдавать ответ в формате JSON который одной функцией превращается в массив:
https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/response_structure-docpage/
Реши тогда задачу про определение адреса.
Не забудь сделать проверки на сетевые ошибки. и указать разумный таймаут для запроса.
Не пиши все одной простыней, разбивай на действия в функциях или методах.
зазубривать справочники не надо, но прочесть (не запоминая) эту страницу с опциями придется: http://php.net/manual/ru/function.curl-setopt.php
> Как скачать сайт курлом, не wgetом?
О, кстати, хорошая задача, можешь ее тоже сделать. Тебе понадобится очередь или массив для хранения старниц которые надо скачать в будущем.
> Как загрузить/скачать файлы по ftp на хостинг (если они это позволяют, конечно)?
Смотри опции курла, он поддерживает FTP, как минимум скачивание. насчет закачки я не помню, если нет то надо либо найти библиоеку для FTP либо написать свою функцию, изучив протокол FTP, он простой и текстовый. думаю, это полезно, заодно научишься с TCP сокетами работать.
> а тупо зазубривать команды, не понимая их смысла не охота.
Так у курла всего несколько функций надо знать, там правда опций много но наизусть их знать не надо.
Ну и я не советую использовать курл напрямую, я советую в приложениях исопльзовать библиотеку HTTP клиента с удобным синтаксисом, напрмер Guzzle или Buzz, так как код на сыром курле смотрится плохо и плохо читается, часто также он содержит ошибки или отстутствие проверок результата. Меня он раздражает.
Конечно это не относится к учебному коду. для изучения курл можно использовать напрямую.
> Я уже писал, но там тупо гоняются json-строки, это не дело, надо через сокеты.
Веб-сокеты и просто сокеты разные вещи, я имел в виду именно обычные сокеты, то есть TCp-соединения и UDP-пакеты. Вебсокеты поверх них построены и их имеет смысл наверно чут позже изучить (хотя можно и наоборот, они не сложные вроде).
> verbose наверное, опции b я не нашел.
В виндоуз она показывает программу занявшую порт. В линукс это опция
> -p, --program
> Show the PID and name of the program to which each socket belongs.
> Давай я пока побалуюсь немного с курлом
Тогда можешь сделать задачу про определение адреса через яндекс-API. Если не хочешь заморочиться с XMl, то геокодер позволяет отдавать ответ в формате JSON который одной функцией превращается в массив:
https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/response_structure-docpage/
Реши тогда задачу про определение адреса.
Не забудь сделать проверки на сетевые ошибки. и указать разумный таймаут для запроса.
Не пиши все одной простыней, разбивай на действия в функциях или методах.
зазубривать справочники не надо, но прочесть (не запоминая) эту страницу с опциями придется: http://php.net/manual/ru/function.curl-setopt.php
> Как скачать сайт курлом, не wgetом?
О, кстати, хорошая задача, можешь ее тоже сделать. Тебе понадобится очередь или массив для хранения старниц которые надо скачать в будущем.
> Как загрузить/скачать файлы по ftp на хостинг (если они это позволяют, конечно)?
Смотри опции курла, он поддерживает FTP, как минимум скачивание. насчет закачки я не помню, если нет то надо либо найти библиоеку для FTP либо написать свою функцию, изучив протокол FTP, он простой и текстовый. думаю, это полезно, заодно научишься с TCP сокетами работать.
> а тупо зазубривать команды, не понимая их смысла не охота.
Так у курла всего несколько функций надо знать, там правда опций много но наизусть их знать не надо.
Ну и я не советую использовать курл напрямую, я советую в приложениях исопльзовать библиотеку HTTP клиента с удобным синтаксисом, напрмер Guzzle или Buzz, так как код на сыром курле смотрится плохо и плохо читается, часто также он содержит ошибки или отстутствие проверок результата. Меня он раздражает.
Конечно это не относится к учебному коду. для изучения курл можно использовать напрямую.
>Если не хочешь заморочиться с XMl
$json = json_encode(simplexml_load_string($xml_string));
$array = json_decode($json,TRUE);
Или о чем ты?
мимокрокодил
Опиши подробнее как именно ты ставишь и что делаешь. Скриншот ошибки это хорошо но хотелось бы знать как повторить проблему.
>>511020
Тебе придется писать свою функцию для аякса и со временем, наращива я возможности ты придешь к тому что перепишешь половину функции $.ajax
Если не нравится jQuery (мне он тоже не очень нравится) можно найти маленькую только аякс библиотеку или написать свою.
>>510845
Работа низкоквалифицированная и наверно не очень хорошо оплачиваемая если только ты не способен стабильно выполнть большой объем работы без косяков.
Так как знаний много не надо то много конкуренции включая индусов и пакистанцев дерущихся за $1-2 в час.
> Если искать заказы на зарубежных фриланс биржах.
Может выйти так что большую часть времени ты будешь тратить на поиски и переговоры не получая денег.
>>510842
Таблицы объединяют через джойны, если они связаны. Если ты делаешь поиск по нескольким то через UNION.
Также, код у тебя ужасный, я бы убрал PREFIX (кому нужны префиксы в наши дни) и использовал плейсхолдеры вместо переменных.
Алсо что это за название? Ты издеваешься?
> user_delet
Что за delet?
> WHERE user_search_pref LIKE '%".$query."%'
Это не индексируется и работает толкьо пока юзеров мало. Плюс, если введено несколько слов то работать не будет номально. Поиск надо делать либо через FULLTEXT индексы либо внешние движки вроде sphinx.
В общем у меня ощущение что тебе рановато писать соцсети и стоит начать с изучения SQL.
> user_country_city_name
Стоит сделать отдельнуб таблицу городов.
Опиши подробнее как именно ты ставишь и что делаешь. Скриншот ошибки это хорошо но хотелось бы знать как повторить проблему.
>>511020
Тебе придется писать свою функцию для аякса и со временем, наращива я возможности ты придешь к тому что перепишешь половину функции $.ajax
Если не нравится jQuery (мне он тоже не очень нравится) можно найти маленькую только аякс библиотеку или написать свою.
>>510845
Работа низкоквалифицированная и наверно не очень хорошо оплачиваемая если только ты не способен стабильно выполнть большой объем работы без косяков.
Так как знаний много не надо то много конкуренции включая индусов и пакистанцев дерущихся за $1-2 в час.
> Если искать заказы на зарубежных фриланс биржах.
Может выйти так что большую часть времени ты будешь тратить на поиски и переговоры не получая денег.
>>510842
Таблицы объединяют через джойны, если они связаны. Если ты делаешь поиск по нескольким то через UNION.
Также, код у тебя ужасный, я бы убрал PREFIX (кому нужны префиксы в наши дни) и использовал плейсхолдеры вместо переменных.
Алсо что это за название? Ты издеваешься?
> user_delet
Что за delet?
> WHERE user_search_pref LIKE '%".$query."%'
Это не индексируется и работает толкьо пока юзеров мало. Плюс, если введено несколько слов то работать не будет номально. Поиск надо делать либо через FULLTEXT индексы либо внешние движки вроде sphinx.
В общем у меня ощущение что тебе рановато писать соцсети и стоит начать с изучения SQL.
> user_country_city_name
Стоит сделать отдельнуб таблицу городов.
>О, кстати, хорошая задача, можешь ее тоже сделать. Тебе понадобится очередь или массив для хранения старниц которые надо скачать в будущем.
>Тебе понадобится очередь
http://codepad.org/FlmoLOwG
>насчет закачки я не помню, если нет то надо либо найти библиоеку для FTP
http://php.net/manual/ru/function.ftp-put.php
>а также JS/CSS/HTML/SQL
Сап /pr/, подкинте годных уроков по изучению JS !!НА ПРАКТИКЕ!!, всегда всё учу именно на практике, я такой человек, что теория в голову ну никак не лезет, по этой причине по началалу не могу читать книги по различным языкам.
Что мне надо? Да любая тема, только бы там объясняли про js в любом его проявлении.
То есть как это, а так - человек что-то делает, описываю это в статье или снимая видео, попутно немного разъясняя, а я повторяю при этом пытаюсь понять как это всё работает, таким боком изучаю.
Как вам вообще такой стиль изучения?
Олифер кстати хороший. нас по моему в универе этими сетевыми технологиями мучали, причем трафик мы изучали не через GUI в Wireshark а дапмили через tcpdump у которой мануал размером сопосставим с моим учеьником PHP. Зато как видишь я теперь в этих технологиях разбираюсь.
Так что читай, экспериментируй, это полезно.
> Это и DNS-адреса где-то кешируются получается?
Это внутренний кеш курла в памяти и он сработает только например когда ресурс делает редирект на том же домене, курл может не отправлять повторно DNS запрос а взять ответ из кеша. Браузеры тоже кешируют DNS так как на каждой странице куча картинок и для каждой делать новый DNS запрос быдо бы медленнее.
> Что такое Accept
Там перечисляется MIME типы которые клиент предпочел бы получить в случае если у сервера есть несколько вариантов ответа. Гугли HTTP Content negotiation:
http://www.google.ru/search?sourceid=chrome&ie=UTF-8&q=HTTP+Content+negotiation
там даже есть ссылка на русском ( http://www.lib.ru/WEBMASTER/rfc2068/section-12.html ). Ну и в стандарте посмотри.
На практике это не используется, и мне не очень нравится. Проще когда сервер дает одинаковый ответ для одинаковых URL.
не работал
>>510336
> На такое согласится только совсем опущенный унтерменш без личной жизни.
почему же? Это зависит от того как ты организуешь свое время, никто не мешает тебе днем учить мануалы а вечером гулять с тян (у которой все равно днем учеба или работа).
Да и погода сейчас такая что днем на улицу вылезать неохота, жарко же.
>>510286
sudo apt-get update сделал? Алсо, погугли текст ошибки из первого скрина.
Алсо погугли debian install postrgresql может ему репозитори какой надо подключить?
На втором скрине опечатка в названии
Ну и локаль ты как-то криво настроил.
>>510258
Нет. В COOKIE записываются пришедшие из браузера в заголовках куки. Это делается до запуска скрипта и в дальнейшем массив не меняется.
>>510155
Наверно.
не работал
>>510336
> На такое согласится только совсем опущенный унтерменш без личной жизни.
почему же? Это зависит от того как ты организуешь свое время, никто не мешает тебе днем учить мануалы а вечером гулять с тян (у которой все равно днем учеба или работа).
Да и погода сейчас такая что днем на улицу вылезать неохота, жарко же.
>>510286
sudo apt-get update сделал? Алсо, погугли текст ошибки из первого скрина.
Алсо погугли debian install postrgresql может ему репозитори какой надо подключить?
На втором скрине опечатка в названии
Ну и локаль ты как-то криво настроил.
>>510258
Нет. В COOKIE записываются пришедшие из браузера в заголовках куки. Это делается до запуска скрипта и в дальнейшем массив не меняется.
>>510155
Наверно.
> MAIN_INSPECT_ACTIVE_TAB;
принято в начале писать что значит константа, то есть ACTIVE_TAB_INSPECT, чтобы все однотипные константы одинаково начинались.
Я не понимаю зачем для одного действия нам 2 файла:
/inspect.php
/scripts/inspect_action.php
Перенеси-ка все из второго в первый и удали inspect_action.php.
> https://github.com/Si0n/register3/blob/master/inspect.php#L6
> require './scripts/messages.php';
Я думаю, проверку сообщений можно перенести в ini.php. И вообще, оставь там только require '...ini.php';
> IMAGE_CRP_SIZE
Не стоит сокращать ради одной буквы. Лучше писать CROP. Вообще, не стоит сокращать названия.
> https://github.com/Si0n/register3/blob/master/scripts/inspect_action.php#L11
> if ($ID == '')
> {
> $ID = $student->getID();
> }
> $profileByID = $db->findStudentByID($ID);
Если у тебя уже загружен объект студента, какой смысл загружать его второй раз? тут надо переписать на if/else.
> $db = new StudentsMapper($pdo);
Одинаковые вещи надо назвать одинаково:
$studntMapper = new StudentMapper
чтобы не создавать путаницу.
> $student = new Student();
> $student->setFieldsWithWhiteSpaces();
Можно сделать чтобы у полей по умолчанию были нужные значения и тогда вызывать функцию не придется.
> https://github.com/Si0n/register3/blob/e2c034bf4563363908504cec9ba6846ae2ded121/scripts/messages.php
Это надо перенести в функцию и удалить этот файл.
Еще кое-что. Файл ini.php у тебя становится слишком большой и в нем слишком много переменных. Если что-то из него можно вынести в функции, стоит это сделать.
> $photoError = FALSE; //ошибки по загрузке фото, которые в случае ошибок заполнятся в savePhoto.php, и выведутся в inspect.php
Это надо перенести в файл работающий с загрузкой фотографий.
> $register = FALSE; // =>savePhoto.php, reg.php => TRUE = > обрабатывается в edit.php
Это наверно перенести в файл работы с формой регистрации. Зачем оно в savePhoto?
> $ID = isset($_GET['ID']) ? $_GET['ID'] : '' ;
> $err = isset($_GET['err']) ? 'Вы ничего не ввели, либо использовали недопустимые символы' : FALSE ;
Это перенести туда где оно используется.
> $search = '';
это в файл вывода списка студентов, если он используется только там. Если везде то можно оставить.
Константы перенеси-ка в functions.php
> $headerMessage = 'К сожалению, Вас нет в списке студентов.';
Я думаю, эту переменную можно убрать, а в шаблоне проверять есть ли id у студента или нет и соовтетственно выводить разные сообщения в этом случае.
> https://github.com/Si0n/register3/blob/master/scripts/ini.php#L33
Чему будет равна переменная $student если студент не найден в базе и if не сработал?
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L4
> $recordsPerPage = 4; //Количество результатов на страницу, для теста 4
> $takeRes = 4; //сколько взять результатов
Это разве не одно и то же? Тогда зачем 2 переменных?
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L20
Вот тут есть несколько ифов, которые выставляют значения вроде $tablePanelHeadingText = TAB_HEADER_WRONG_REQUEST;
Так ли нам нужна эта переменная? Нельзя просто эти ифы перенести в шаблон?
> } elseif ($students == 'failed')
Хотя это конечно не перенесешь. Лучше наверно при передаче неправильного имени поля потихому его исправлять на поле по умолчанию и тогда эта проверка станет не нужна.
> https://github.com/Si0n/register3/blob/master/lib/Image.php#L65
> $src = 'E:/OpenServer/domains/localhost/php/register3/upload/'. 'full-'.$name;
Это неправильно. Как я запущу твой проект если у меня папка другая? Надо либо вынести путь в конфиг либо (что лучше) определять его в ini.php автоматически через константу _ _ DIR _ _
> https://github.com/Si0n/register3/blob/master/inspect.php#L14
После успешной обработки формы надо редиректить и завершать скрипт.
Если файл list_action.php подключается только здесь то лучше перенести его содержимое сюда.
> error_reporting(-1);
> ini_set('display_errors', 1);
Это перенеси в ini.php, не надо эти строчки копипастить в каждый скрипт.
> https://github.com/Si0n/register3/blob/master/messages.sql#L29
В таблице messages добавь внешние ключи как описано тут: http://denis.in.ua/foreign-keys-in-mysql.htm
Не забудь обновить файл messages.sql
> UNIQUE KEY `id_message` (`id_message`)
Это правильнее сделать первичным ключом так как первычный ключ это уникальный идентификатор записи и тут как раз такой случай.
В проверку валидности сообщения добавь проверку валидности id автора и id_target. для этого придется наверно вызвать другие мапперы, рабтающие с этим и таблицами.
Пока все, как исправишь, проверим еще.
Не жди пока я проверю, делай какие-то другие фичи или задания.
> MAIN_INSPECT_ACTIVE_TAB;
принято в начале писать что значит константа, то есть ACTIVE_TAB_INSPECT, чтобы все однотипные константы одинаково начинались.
Я не понимаю зачем для одного действия нам 2 файла:
/inspect.php
/scripts/inspect_action.php
Перенеси-ка все из второго в первый и удали inspect_action.php.
> https://github.com/Si0n/register3/blob/master/inspect.php#L6
> require './scripts/messages.php';
Я думаю, проверку сообщений можно перенести в ini.php. И вообще, оставь там только require '...ini.php';
> IMAGE_CRP_SIZE
Не стоит сокращать ради одной буквы. Лучше писать CROP. Вообще, не стоит сокращать названия.
> https://github.com/Si0n/register3/blob/master/scripts/inspect_action.php#L11
> if ($ID == '')
> {
> $ID = $student->getID();
> }
> $profileByID = $db->findStudentByID($ID);
Если у тебя уже загружен объект студента, какой смысл загружать его второй раз? тут надо переписать на if/else.
> $db = new StudentsMapper($pdo);
Одинаковые вещи надо назвать одинаково:
$studntMapper = new StudentMapper
чтобы не создавать путаницу.
> $student = new Student();
> $student->setFieldsWithWhiteSpaces();
Можно сделать чтобы у полей по умолчанию были нужные значения и тогда вызывать функцию не придется.
> https://github.com/Si0n/register3/blob/e2c034bf4563363908504cec9ba6846ae2ded121/scripts/messages.php
Это надо перенести в функцию и удалить этот файл.
Еще кое-что. Файл ini.php у тебя становится слишком большой и в нем слишком много переменных. Если что-то из него можно вынести в функции, стоит это сделать.
> $photoError = FALSE; //ошибки по загрузке фото, которые в случае ошибок заполнятся в savePhoto.php, и выведутся в inspect.php
Это надо перенести в файл работающий с загрузкой фотографий.
> $register = FALSE; // =>savePhoto.php, reg.php => TRUE = > обрабатывается в edit.php
Это наверно перенести в файл работы с формой регистрации. Зачем оно в savePhoto?
> $ID = isset($_GET['ID']) ? $_GET['ID'] : '' ;
> $err = isset($_GET['err']) ? 'Вы ничего не ввели, либо использовали недопустимые символы' : FALSE ;
Это перенести туда где оно используется.
> $search = '';
это в файл вывода списка студентов, если он используется только там. Если везде то можно оставить.
Константы перенеси-ка в functions.php
> $headerMessage = 'К сожалению, Вас нет в списке студентов.';
Я думаю, эту переменную можно убрать, а в шаблоне проверять есть ли id у студента или нет и соовтетственно выводить разные сообщения в этом случае.
> https://github.com/Si0n/register3/blob/master/scripts/ini.php#L33
Чему будет равна переменная $student если студент не найден в базе и if не сработал?
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L4
> $recordsPerPage = 4; //Количество результатов на страницу, для теста 4
> $takeRes = 4; //сколько взять результатов
Это разве не одно и то же? Тогда зачем 2 переменных?
> https://github.com/Si0n/register3/blob/master/scripts/list_action.php#L20
Вот тут есть несколько ифов, которые выставляют значения вроде $tablePanelHeadingText = TAB_HEADER_WRONG_REQUEST;
Так ли нам нужна эта переменная? Нельзя просто эти ифы перенести в шаблон?
> } elseif ($students == 'failed')
Хотя это конечно не перенесешь. Лучше наверно при передаче неправильного имени поля потихому его исправлять на поле по умолчанию и тогда эта проверка станет не нужна.
> https://github.com/Si0n/register3/blob/master/lib/Image.php#L65
> $src = 'E:/OpenServer/domains/localhost/php/register3/upload/'. 'full-'.$name;
Это неправильно. Как я запущу твой проект если у меня папка другая? Надо либо вынести путь в конфиг либо (что лучше) определять его в ini.php автоматически через константу _ _ DIR _ _
> https://github.com/Si0n/register3/blob/master/inspect.php#L14
После успешной обработки формы надо редиректить и завершать скрипт.
Если файл list_action.php подключается только здесь то лучше перенести его содержимое сюда.
> error_reporting(-1);
> ini_set('display_errors', 1);
Это перенеси в ini.php, не надо эти строчки копипастить в каждый скрипт.
> https://github.com/Si0n/register3/blob/master/messages.sql#L29
В таблице messages добавь внешние ключи как описано тут: http://denis.in.ua/foreign-keys-in-mysql.htm
Не забудь обновить файл messages.sql
> UNIQUE KEY `id_message` (`id_message`)
Это правильнее сделать первичным ключом так как первычный ключ это уникальный идентификатор записи и тут как раз такой случай.
В проверку валидности сообщения добавь проверку валидности id автора и id_target. для этого придется наверно вызвать другие мапперы, рабтающие с этим и таблицами.
Пока все, как исправишь, проверим еще.
Не жди пока я проверю, делай какие-то другие фичи или задания.
Это всего лишь подключение кастомных шрифтов с помощью flash по моему (в наше время не треубется, новые браузеры умеют поддерживать загружаемые шрифты без флеша и яваскрипта).
Судя по расшиению это шаблоны.
>>513233
> то что ты вообще в вебе делаешь? чисто задачки из ОП-поста решаешь?
Я не решаю, а составляю задачки, пишу уроки и проверяю решения.
Мне не охота за тебя читать документацию к твоей CMS. У меня своей работы достаточно.
>>513238
Тот кто делал тот проект тоже так думал.
Надо писать хороший и поддерживаемый код чтобы про тебя потом так же не говорили.
>>513242
Надо читать доки и иногда смотреть в код и сравнивать. Как насчет посмотреть на несложный контейнер из фреймворка Slim?
http://docs.slimframework.com/di/overview/
https://github.com/slimphp/Slim/blob/2.x/Slim/Helper/Set.php
как видишь он напоминает массив с методами.
Микрофреймворк Silex ( http://silex.sensiolabs.org/doc/services.html ) использует Pimple ( http://pimple.sensiolabs.org/ ) как контейнер (там основной класс от него унаследован):
https://github.com/silexphp/Pimple
https://github.com/silexphp/Pimple/blob/master/src/Pimple/Container.php
Тоже по сути массив с методами.
Имей в виду что это решения для микрофреймворков.
Это всего лишь подключение кастомных шрифтов с помощью flash по моему (в наше время не треубется, новые браузеры умеют поддерживать загружаемые шрифты без флеша и яваскрипта).
Судя по расшиению это шаблоны.
>>513233
> то что ты вообще в вебе делаешь? чисто задачки из ОП-поста решаешь?
Я не решаю, а составляю задачки, пишу уроки и проверяю решения.
Мне не охота за тебя читать документацию к твоей CMS. У меня своей работы достаточно.
>>513238
Тот кто делал тот проект тоже так думал.
Надо писать хороший и поддерживаемый код чтобы про тебя потом так же не говорили.
>>513242
Надо читать доки и иногда смотреть в код и сравнивать. Как насчет посмотреть на несложный контейнер из фреймворка Slim?
http://docs.slimframework.com/di/overview/
https://github.com/slimphp/Slim/blob/2.x/Slim/Helper/Set.php
как видишь он напоминает массив с методами.
Микрофреймворк Silex ( http://silex.sensiolabs.org/doc/services.html ) использует Pimple ( http://pimple.sensiolabs.org/ ) как контейнер (там основной класс от него унаследован):
https://github.com/silexphp/Pimple
https://github.com/silexphp/Pimple/blob/master/src/Pimple/Container.php
Тоже по сути массив с методами.
Имей в виду что это решения для микрофреймворков.
Заведи блог и пиши. Это бесплатно.
>>513254
А где проверка ошибок? Это плохой код. Также XML невыгодно превращать в JSON так как ты тераяешь возмодность использовать XPath например.
Ну и яндекс API и так умеет отдавать JSON если хорошо попросить.
>>513256
Это скчивание однй страницы причем простыней без разбинения на функции.
> url_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko)
Так неправильно писать в учебном примере. Код должен учить хорошим практикам и объяснять каждую опцию.
> curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false);
>\t\tcurl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, false);
Это требует объяснений. И небезопасно.
> if(is_array($headers))
А если не массив?
Также нет проверки результата.
Код плохой.
Это лучше сделать не функцией с 100500 аргументов а классом. В 99% случаев тебе не нужен прокси например.
Заведи блог и пиши. Это бесплатно.
>>513254
А где проверка ошибок? Это плохой код. Также XML невыгодно превращать в JSON так как ты тераяешь возмодность использовать XPath например.
Ну и яндекс API и так умеет отдавать JSON если хорошо попросить.
>>513256
Это скчивание однй страницы причем простыней без разбинения на функции.
> url_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko)
Так неправильно писать в учебном примере. Код должен учить хорошим практикам и объяснять каждую опцию.
> curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, false);
>\t\tcurl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, false);
Это требует объяснений. И небезопасно.
> if(is_array($headers))
А если не массив?
Также нет проверки результата.
Код плохой.
Это лучше сделать не функцией с 100500 аргументов а классом. В 99% случаев тебе не нужен прокси например.
Это же нечитаемая простыня. Есть ограничение глубины ссылок, ограничение по путям и доменам? Это не учебный пример, он если чему и учит то дурным практикам.
Плюс асинхронный курл требует удобного интерфейса. А тут вообще непонтяно корректно он реализован и все ли ситуации обрабатываются.
learn.javascript.ru читал?
ПРежде чем заниматься практикой надо выучить сам язык программирования. Перепсывание кода с экрана ничего не дает.
> Как вам вообще такой стиль изучения?
Ты ничему так не науичшься и свалишься на первом же вопросе на соеседовании.
По сути нужно пройтись по популярным методам, а справочник ломает читать.
>Это скчивание однй страницы причем простыней без разбинения на функции.
Ну я не так понял, значит. Алсо, для этого курл и не нужен тогда.
>Так неправильно писать в учебном примере.
Неправильно что? Функция для эмуляции запросов из браузера, обычная установка юзерагента, а уж какой туда засунуть - другое дело.
>Это требует объяснений. И небезопасно.
И не нужно ебаться с валидацией сертификатов, когда тебе это не нужно вообще. А так:
curl_setopt($ch, CURLOPT_SSLCERT, 'cert.pem');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD,'certpass');
>А если не массив?
Очевидно что if не сработает, не?
>Также нет проверки результата.
Не в этой функции это надо делать, ибо можно обращаться к сотням разных сервисов, и что, под каждый писать свою обработку? На что проверять результат? В ответе тебе и так приходят заголовки, а если ты про ошибки курла, то опять же добавить всего пару строчек:
$response = curl_exec($ch);
if(curl_errno($ch))
{
echo 'curl error: ' . curl_error($ch);
error_wrapper(curl_errno($ch));
}
>Код плохой. Это лучше сделать...
Ты уж покажи тогда как сделать хорошо, и не тянуть за собой огромные движки, тонну ненужного в данных целях ООП и прочего.
>В 99% случаев тебе не нужен прокси например.
Поэтому там есть дефолтные значение и определенный порядок.
Алсо, я просто в качестве мини-примера запостил, в самом простом варианте, а там уж кому надо допилит и переделает под свои вкусы.
>Это скчивание однй страницы причем простыней без разбинения на функции.
Ну я не так понял, значит. Алсо, для этого курл и не нужен тогда.
>Так неправильно писать в учебном примере.
Неправильно что? Функция для эмуляции запросов из браузера, обычная установка юзерагента, а уж какой туда засунуть - другое дело.
>Это требует объяснений. И небезопасно.
И не нужно ебаться с валидацией сертификатов, когда тебе это не нужно вообще. А так:
curl_setopt($ch, CURLOPT_SSLCERT, 'cert.pem');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD,'certpass');
>А если не массив?
Очевидно что if не сработает, не?
>Также нет проверки результата.
Не в этой функции это надо делать, ибо можно обращаться к сотням разных сервисов, и что, под каждый писать свою обработку? На что проверять результат? В ответе тебе и так приходят заголовки, а если ты про ошибки курла, то опять же добавить всего пару строчек:
$response = curl_exec($ch);
if(curl_errno($ch))
{
echo 'curl error: ' . curl_error($ch);
error_wrapper(curl_errno($ch));
}
>Код плохой. Это лучше сделать...
Ты уж покажи тогда как сделать хорошо, и не тянуть за собой огромные движки, тонну ненужного в данных целях ООП и прочего.
>В 99% случаев тебе не нужен прокси например.
Поэтому там есть дефолтные значение и определенный порядок.
Алсо, я просто в качестве мини-примера запостил, в самом простом варианте, а там уж кому надо допилит и переделает под свои вкусы.
learn.javascript.ru не читал, почитаю.
Это не тупое переписывание кода с экрана, конечно просто бездумное переписывание даст чуть более чем ничего. Я же при написании чего либо стараюсь понять, что я написал, как это работает и т.д, таким образом информация отлично отлаживаеться в голове.
Сначала таким образом хочу выучить чуть более основ, а потом уже смогу нормально читать книги по теме.
Я не очень советую learn.javascript.ru. Поначалу там все хорошо, но потом какая-то хуйня начинается ближе к концу. Куча всякой лишней инфы, какие-то ебанутые вставки с примечаниями аля "это инфа прост тут, можете не читать)))0" и прочая херня.
Советую посмотреть курс от неких ITVDN, там все подробно разжевывается. Иногда даже чересчур. Но если что мотануть можно. Правда он платный, но при желании можно всегда на торрентах его купить.
анон со схожим стилем обучения
В курсе специалиста происходит так как ты хочешь. Если конспектировать, то материал легко усвоится, ну кроме замыканий, даже блондинкой. Чистый ЖС - самая сложная часть, DOM вообще легкотня, события тоже, хотя всплытие заставило поломать голову. jQuery тоже ничего сложного.
Диржи http://nnm-club.me/?q=%F1%EF%E5%F6%E8%E0%EB%E8%F1%F2+javascript+2014&w=title
Ты еще криво не видел. Это ок. Хотя попробуй по-человечески, через @font-face.
У него вся страница динамически из темплейтов отрисована и каждый текст канвасом в свг отрисовывается через инпут в админке. ояхуею как это редактировать вообще.
это хуйня из датабазы отрисовывается, а в дб через инпут в админке засовывается, там ПРОСТО БУКОВКАМИ в хтмл тегах не напишешь это.
Предложение проебал
Сделай просто треугольник, при нажатии котором колонка сортируется по ORDER BY.
Только есть одно но: в условии строуберрибанка есть плата за открытие счета, которую надо сделать единожды, а не через цикл. Не могу понять, как сделать это. Помогите, антошки.
>Тут много ошибок, например не кодируются параметры в URL, никак не обрабатываются сетевые ошибки, непонятно почему текст разбивается на куски по 3 слова, слова могут быть разделены не только проблелом,
Это всё понятно, это черновик, текст разбивается по 3 слова по тому что именно так чаще всего проверяют текст на уникальность, то есть шингл = 3, а как кроме пробелов могут разделяться слова? запятыми, точками и восклицательными знаками? Ну в этом случае всё равно есть пробелы, а если они не нужны для проверки на уникальность их можно просто почистить, заменить все эти символы на ничто например, ну не в этом дело, меня интересует сама технология, как это вообще делается? Если откинуть все недоработки, сама основа скрипта верная, так это делается или нет? Много же существует ресурсов для проверки уникальности, как они это сделали?
Твой пример содержит ошибки и не содержит объяснений. Плюс у тебя тараканы в голове в виде представления о «ненужном» ООП. Это не годится как учебный пример, так как учеьный пример должен учить правильным техникам и объяснять.
В качестве User-Agnet очевидно принято указывать название библиотеки а не прикидываться браузером (что легко проверить при желании).
> я просто в качестве мини-примера запостил
пример как делать не надо.
PHP (вместе с Pascal) — самые низкооплачиваемые языки программирования. Сколько бы книг ты ни прочитал, сколько бы мегабайт кода ни написал, ты никогда не будешь получать больше, чем Java-быдлокодер средней криворукости. «На Яве пишут Корпорации», а на Пыхе…Порог выхода такой же низкий, как и порог входа: если у программиста на полноценных языках с возрастом есть шанс стать ценным высокооплачиваемым специалистом, то у похапе-олдфага такой возможности нет просто ввиду убогости и примитивности решаемых задач. Его спокойно можно выгнать на улицу, взяв взамен школьника, который обучится всем премудростям похапе-быдлокоддинга за пару месяцев, потребляя при этом в три раза меньше доширака.Возможно, сейчас тебе кажется, что делать сайты — достойное и интересное занятие, но если ты хоть немного программист, через пару лет такой работы ты просто завоешь от того, насколько это унылая и далекая от программирования деятельность.Большинство проектов кроме того, что по сути своей убоги, представляют из себя чудовищный говнокод на кривых самодельных говнофреймворках и говноCMS (потому как сам язык не только не заставляет писать правильно, но и фактически подталкивает к производству быдловелосипедов). Как следствие такой работы — необратимое поражение мозга и окончательная потеря квалификации. Чему также способствует работа в коллективе невероятно тупых похапешников, постоянные оскорбления и обвинения (просто потому, что умный человек PHP не выберет).Некоторые начинают работать на PHP с надеждой потом перейти на что-нибудь другое. Но это тоже большая ошибка: во-первых, теряется драгоценное время для старта (наверное, самое важное и ценное в и без того короткой профессиональной жизни программиста), а во-вторых, PHP-опыт никому не нужен и нормальные программисты справедливо смотрят на него как на говно. «PHP» — клеймо быдлокодера на лбу и крест на карьере профессионального программиста, если ты пошёл по этому пути, назад дороги уже не будет. Единственное исключение — устроится похапешником на многопрофильную фирму, где тебя каким-то чудом заметят и предложат перейти на полноценную технологию, но это невероятная удача.Чуть более, чем вся относительно хорошо оплачиваемая работа для похапешников состоит из поддержки ботнетов, порносайтов, говносайтов с вирусами и прочего подобного дерьма. Подумай, хочешь ли ты потратить свою жизнь на засирание интернетов.
PHP погубил очень много потенциально хороших программистов просто благодаря легкости изучения на начальных этапах. Он затягивает как наркотик, с ним очень легко и приятно начать, вот только когда приходит понимание принципиальных недостатков как самого языка, как и (что гораздо более важно) его убогой ниши — часто оказывается уже слишком поздно что-то менять. Так что учись программировать, думай о будущем и обходи PHP стороной. Потому что с PHP у тебя нет будущего — это путь в никуда.
PHP (вместе с Pascal) — самые низкооплачиваемые языки программирования. Сколько бы книг ты ни прочитал, сколько бы мегабайт кода ни написал, ты никогда не будешь получать больше, чем Java-быдлокодер средней криворукости. «На Яве пишут Корпорации», а на Пыхе…Порог выхода такой же низкий, как и порог входа: если у программиста на полноценных языках с возрастом есть шанс стать ценным высокооплачиваемым специалистом, то у похапе-олдфага такой возможности нет просто ввиду убогости и примитивности решаемых задач. Его спокойно можно выгнать на улицу, взяв взамен школьника, который обучится всем премудростям похапе-быдлокоддинга за пару месяцев, потребляя при этом в три раза меньше доширака.Возможно, сейчас тебе кажется, что делать сайты — достойное и интересное занятие, но если ты хоть немного программист, через пару лет такой работы ты просто завоешь от того, насколько это унылая и далекая от программирования деятельность.Большинство проектов кроме того, что по сути своей убоги, представляют из себя чудовищный говнокод на кривых самодельных говнофреймворках и говноCMS (потому как сам язык не только не заставляет писать правильно, но и фактически подталкивает к производству быдловелосипедов). Как следствие такой работы — необратимое поражение мозга и окончательная потеря квалификации. Чему также способствует работа в коллективе невероятно тупых похапешников, постоянные оскорбления и обвинения (просто потому, что умный человек PHP не выберет).Некоторые начинают работать на PHP с надеждой потом перейти на что-нибудь другое. Но это тоже большая ошибка: во-первых, теряется драгоценное время для старта (наверное, самое важное и ценное в и без того короткой профессиональной жизни программиста), а во-вторых, PHP-опыт никому не нужен и нормальные программисты справедливо смотрят на него как на говно. «PHP» — клеймо быдлокодера на лбу и крест на карьере профессионального программиста, если ты пошёл по этому пути, назад дороги уже не будет. Единственное исключение — устроится похапешником на многопрофильную фирму, где тебя каким-то чудом заметят и предложат перейти на полноценную технологию, но это невероятная удача.Чуть более, чем вся относительно хорошо оплачиваемая работа для похапешников состоит из поддержки ботнетов, порносайтов, говносайтов с вирусами и прочего подобного дерьма. Подумай, хочешь ли ты потратить свою жизнь на засирание интернетов.
PHP погубил очень много потенциально хороших программистов просто благодаря легкости изучения на начальных этапах. Он затягивает как наркотик, с ним очень легко и приятно начать, вот только когда приходит понимание принципиальных недостатков как самого языка, как и (что гораздо более важно) его убогой ниши — часто оказывается уже слишком поздно что-то менять. Так что учись программировать, думай о будущем и обходи PHP стороной. Потому что с PHP у тебя нет будущего — это путь в никуда.
Ты бы (или он бы) документацию по cufon почитал для начала.
>>513298
Сделай заголовок колонки ссылкой вида index.php?sort=name
Алсо в комментариях к задаче разве это не написано?
>>513329
Перед началом цикла прибавь эти 7777 к сумме долга.
>>513332
> текст разбивается по 3 слова по тому что именно так чаще всего проверяют текст на уникальность, то есть шингл = 3,
Какой еще шингл? Для поиска в гугле они тебе не нужны.
Алсо для сеошников есть раздел /web.
>(вместе с Pascal) — самые низкооплачиваемые языки программирования.
Подскажи куда устроиться на паскале программировать.
Ткните, пожалуйста, в чем она?
http://ideone.com/5ZiBQT
У меня вообще не отправляется, а у них сук по три раза.
В блокноте погромируешь?
http://ideone.com/xSPWmX
По-твоему это много?
У меня в файлообменнике 461 строка php-кода, не считая js, css и html.
И это простейшее хелловорлдное приложение, его за два дня можно написать, если знать как.
На больших фреймворках проекты могут спокойно переваливать за десятки тысяч строк.
А как в них не путаются потом? По-моему в чужом коде вообще бесполезно ковырять, потмоу что не ты писал..
Именно поэтому мы и учим тут ООП. Все очень логично упаковано в классы, сами классы соответствуют паттернам.
Например если ты видишь какой-нибудь UserMapper, то сразу можешь понять: "ага, это же известнейший паттерн DataMapper, у него точно есть методы для работы с базой данных для сохранения, обновления или удаления записей". Я даже не залезая внутрь этого класса знаю, что внутри него находится и как он устроен! В этом суть ООП, в четкой логичной структуре.
Или вот я вижу запись типа $app = Applicattion::getInstance();
Я сразу понимаю, что это паттерн синглтон, и что объект $app у меня все время будет один и тот же, не будет двух его копий по всему проекту.
И так далее. То есть все очень хорошо стандартизировано. Это как раз функциональный код совершенно неудобный, нечитабельный и нередактируемый: тут какая-то функция. Лезем в файл с функциями, поиском ее находим, в ней вызывается еще десять функций с невнятными названиями. Лезем в каждую из этих десяти. Там творится тоже какая-то неведомая хрень, и вызываются другие функции с ни о чем не говорящими именами. В результате ты не имеешь никакого представления, что, куда и зачем, как эта хрень вообще между собой связана и как оно работает. Если попытаешься что-то редактировать, то это потянет за собой еще кучу правок.
Так написано большинство cms, и именно за это их не любят.
В ООП все четко, последовательно, все связи даже рисуют на uml-диаграммах, и разобраться что и где не составит труда и времени. Это похоже на схемы баз данных, если ты работал в Воркбенче например. Пикрелейтед.
Но учиться конечно нужно очень много.
Для общего развития можешь на хабре почитать
http://habrahabr.ru/post/214285/
http://habrahabr.ru/post/210288/
Или послушать лекции Борисова (4 курс php), он неплохо объясняет.
Но это сейчас не важно. Без практического применения все равно мало поймешь.
Решай задания ОПа, когда дойдешь до файлообменника, будешь тащиться от красоты объектно-ориентированного кода, я гарантирую это.
Затем когда будешь учить большие фреймворки, там эти шаблоны друг на друге сидят и шаблоном погоняют, и это правильно и здорово.
Ну и потом уже можно будет почитать хардкорный первоисточник, книгу Мартина Фаулера "Шаблоны проектирования".
>>513435
Хз, я из гугла взял. И вообще я хуй простой, мне просто нравится всех поучать с умным видом.
>Это как раз функциональный код совершенно неудобный, нечитабельный и нередактируемый: тут какая-то функция. Лезем в файл с функциями, поиском ее находим, в ней вызывается еще десять функций с невнятными названиями.
Ойнинада приёмы кодирования везде одинаковы. Вот функция scan_files получает на вход переменные path и mask и ещё одну функцию, догадайся что она делает. А вот такая же функция scan_words, получает на вход строку... продолжать?
Догадаться можно если у переменных хорошие названия или если комментарий есть.
Ну и общепринятые подходы это хорошо. Разбирать MVC код на Юи гораздо легче чем на самописаной CMS.
Scan_words мне ни о чем не говорит. Ну да, оно сканирует какие-то слова. А к чему эта функция вообще относится? Что за words? Это относится к валидации? Или может быть вообще к чему-то другому? Если к валидации, то валидации чего? Какой-то формы? Какой?
Вот-вот.
А в ООП все четенько, каждый метод строго относится к классу, а класс точно описывает объект. Классы можно наследовать, если объект нужно слегка изменить. А твоя функция заточена под какие-то условия, и ее нужно либо переписывать, либо копипастить в новую функцию и уже там менять.
>А твоя функция заточена под какие-то условия, и ее нужно либо переписывать, либо копипастить в новую функцию и уже там менять.
ВЫ ВСЁ ВРЁТИ.
Я дополню её другой функцией, подам на вход. Слова она выбирает из строки, не надо там ничего переписывать, цикл while это.
Вообще, такое ощущение, что я делаю сайт 14летней девочке.
Привет, до сих пор работаю на этом поприще уже как второй год, вот пытаюсь перейти на ПХП.
>Какой еще шингл? Для поиска в гугле они тебе не нужны.
Так уникальность проверяется, то есть смотри как найти совпадение с другим текстом в интернете, надо проверить текст по частям, разбивать на 3 слова самый удачный вариант, так как если разбить на два слова то почти все тексты в сети будут не уникальными, а на 4 уже довольно много, 3 идеально, как у Пифагора.
да, я очень рад за ООП, но ковыряться-то мне приходится в цмс.
function __autoload($class_name) {
include $class_name . '.php';
}
$obj = new MyClass1();
$obj2 = new MyClass2();
Как эта функция определяет какой класс надо подключить? И как она вообще его находит?
Ну в php вшито, что если он не может найти класс, то не орать об ошибке, а исполнить функцию __autoload, подставив в нее в качестве аргумента имя отсутствующего класса. А внутри функции тупо подставляется это имя, и файл подключается. Но это сработает, только если ты будешь называть файлы с классами так же, как и сами классы, разумеется.
с конфигами все нормальное, нулевая частично отрисовывается (а вот стили и пути к товарам - нет). эх, пичклька, уже второй день из пяти, а я до сих пор не могу даже копнуть цмску, потому что у меня она нихуя не работает на локалке, в слепую же не править, право.
\t\t\t$_SESSION['admins'] = "";
\t\t\techo $common->re("0", "admin/");
\t\tbreak;
Говорит ли это о том, что при разлогинивании сессия удаляется?
Ясно, спасибо, вот ещё один момент не могу никак понять, как работает вот эта вещь?
set_include_path(get_include_path()
.PATH_SEPARATOR . "путь к папке1".
PATH_SEPARATOR . "путь к папке2".
PATH_SEPARATOR . "путь к папке");
И как она помогает при аутолоаде, у меня выбивает ошибку.
Если в бэкенде проверки на принадлежность к европкам нет, то элементарно обходится, достаточно код странички подправить.
interpals.com
Написан он очень криво, сейчас при частом обновлении он мне на профиль накинул метку, мол, я не могу этому пользователю писать.
Отправляет он коммент формой.
pid - id фотки.
uid - user id (он подставляется после отправки запроса)
aid - так и не понял что это. Возможно какой-то action id.
Остальные поля, думаю, понятно.
Щя проверю на других страницах action id.
>2 пик
Стоп, но это параметры, которые летят на BE. это получается, что uid подставляется ещё до отправки. И если нет валидации, можно под любым пользователем писать что хочешь?!
Вангую, там cookies и session.
Я себе чуть очко не порвал когда понял что ошибкой было вместо этого:
$monthlyPayment = $creditBalance; (правильно)
вот эта хуета:
$creditBalance = $monthlyPayment;
я сидел весь день над этим, чувствую себя макакой
Ты серьезно? Я ее в голове решил за 30 секунд. На худой конец можно было дамп всех переменных на экран по очереди делать.
мимокрок
Нет. Я общаюсь с тянками из разных стран, а одна настроила себе страницу так, чтобы ей не писали из Европы. Вот у меня и появился спортивный интерес ей написать.
та хуй его знает, я не могу понять сам ход мыслей при решении подобной хуеты, уже не первый раз замечаю, а вроде и не гуманитарий...
Если понять ход не можешь, дампай все на экран по очереди, пока понятно не станет.
Нет.
Даун ебучий, смени страну в профайле или сделай другой профайл с нужной страной и не еби мозг своими формами.
Сменил страну, написал комент, сменил страну обратно. Тян думает, ты хакир.
спасибо, пожалуй запомню. Ато чот после кодакадеми эти задачки меня в тупик ставят...хотя я понимаю что это детский сад лол
Если вообще без всего, одни темплейты и удалялка/редактилка, то неделю и 500 баксов. Если со стандартными фичами, то недели 2 и тысяча баксов. Ну и дальше в таком же духе в зависимости от количества нужных фич.
http://ideone.com/UZ70da и http://ideone.com/7v0UOe - 2 решения задачи про палиндромы;
http://ideone.com/lxGzZj - задача про айпад в кредит;
http://ideone.com/LI0fa0 - первая задача из урока про регулярные выражения. Встрял со второй, не понимаю.
Вот тут типа черновик http://ideone.com/jzZqix.
Как я думаю - проверку ошибок, чтобы выводить с куском текста, надо делать через preg_match. Но я вот не понимаю, я хочу вывести в массив ошибок каждое из этих слов:
$regexp = '/(Сдесь)|(зделан)|(зделаю)/';
Но в массиве у меня остается только первое слово - "Сдесь". Что я делаю не так?
Все же твой пример плох, так как содержит много ошибок и недоработок и не учит.
А если тебе нужна готовая библиотека лучше брать Guzzle или Buzz или что-нибудь еще с нормальным API а не функцию с 10 параметрами без проверки правильности и непонятно как их передавать. Этим ты экономишь свое время на отладку и разработку. Велосипеды не нужны.
> curl_setopt($ch, CURLOPT_SSLCERTPASSWD,'certpass');
Зачем нужен пароль для набора корневых сертификатов? Ты напутал что-то.
Для HTTPS тебе не нужен свой сертификат с приватным ключем, тебе просто нужен пак корневых сертификатов, например от мозиллы.
Вот комментарий про то как их устанавливать: http://php.net/manual/ru/function.curl-setopt.php#110457
>>А если не массив?
> Очевидно что if не сработает, не?
В таком случае надо не притворяться что все в порядке, а выбросить исключение, иначе как программист узнает об ошибке?
>>Также нет проверки результата.
> Не в этой функции это надо делать
Как минимум надо курловские ошибки обрабатывать, да и всякие 404 тоже желательно бы. Для этого стоит конечно переделать дизайн функции, может исключения выбрасывать.
>>Код плохой. Это лучше сделать...
> Ты уж покажи тогда как сделать хорошо,
Если дял практических целей, взять готовую библиотеку. Если для изучения курла, тут удоюбно применить ООП и сделать методы для задания редкоиспользуемых опций. Вроде такого:
$client = new HttpClient;
$client->setSomeOption(....);
$response = $client->get('http://exxample.com');
// здесь как ты видишь есть подвох в том, что если мы возщвращаем тело страницы то непонятно как получить заголовки, тип ответа, статус ошибки и тд. Нормальные библиотеки решают эту проблему, возвращая не строку, а объект Response. Так что стоит написать еще класс Response, причем для хранения информации о HTTP ответе есть и интерфейс в PSR: http://www.php-fig.org/psr/psr-7/#3-3-psr-http-message-responseinterface
$page = $client->post(....);
// для удобства можно добавить методы-обертки, делающие проверки результата, типа, кода ответа и возвращающие сразу HTML:
$html = $client->getHtmlPage('http://...');
Все же твой пример плох, так как содержит много ошибок и недоработок и не учит.
А если тебе нужна готовая библиотека лучше брать Guzzle или Buzz или что-нибудь еще с нормальным API а не функцию с 10 параметрами без проверки правильности и непонятно как их передавать. Этим ты экономишь свое время на отладку и разработку. Велосипеды не нужны.
> curl_setopt($ch, CURLOPT_SSLCERTPASSWD,'certpass');
Зачем нужен пароль для набора корневых сертификатов? Ты напутал что-то.
Для HTTPS тебе не нужен свой сертификат с приватным ключем, тебе просто нужен пак корневых сертификатов, например от мозиллы.
Вот комментарий про то как их устанавливать: http://php.net/manual/ru/function.curl-setopt.php#110457
>>А если не массив?
> Очевидно что if не сработает, не?
В таком случае надо не притворяться что все в порядке, а выбросить исключение, иначе как программист узнает об ошибке?
>>Также нет проверки результата.
> Не в этой функции это надо делать
Как минимум надо курловские ошибки обрабатывать, да и всякие 404 тоже желательно бы. Для этого стоит конечно переделать дизайн функции, может исключения выбрасывать.
>>Код плохой. Это лучше сделать...
> Ты уж покажи тогда как сделать хорошо,
Если дял практических целей, взять готовую библиотеку. Если для изучения курла, тут удоюбно применить ООП и сделать методы для задания редкоиспользуемых опций. Вроде такого:
$client = new HttpClient;
$client->setSomeOption(....);
$response = $client->get('http://exxample.com');
// здесь как ты видишь есть подвох в том, что если мы возщвращаем тело страницы то непонятно как получить заголовки, тип ответа, статус ошибки и тд. Нормальные библиотеки решают эту проблему, возвращая не строку, а объект Response. Так что стоит написать еще класс Response, причем для хранения информации о HTTP ответе есть и интерфейс в PSR: http://www.php-fig.org/psr/psr-7/#3-3-psr-http-message-responseinterface
$page = $client->post(....);
// для удобства можно добавить методы-обертки, делающие проверки результата, типа, кода ответа и возвращающие сразу HTML:
$html = $client->getHtmlPage('http://...');
Посмотри ошибки внизу, их надо исправить.
> PHP Warning: Missing argument 3 for credit(), called in /home/5LpEvn/prog.php on line 23 and defined in /home/5LpEvn/prog.php on line 5
Ты передал меньше аргументов в функцию чем требуется.
> PHP Notice: Undefined variable: fee in /home/5LpEvn/prog.php on line 6
Обращение к несуществующей (потому что ты ее не передал) переменной.
> \tif ($creditBalance < 0) {
> $paymentTotal = $paymentTotal - $creditBalance;
Это явно неправильно. Ведь если ты вычитаешь отрицательное число то paymentTotal становится больше. ну например:
5000 - (-1000) = 6000
Арифметику школьную забыл?
Решил ли ты задачу про айфон, с одним банком? Я вижу что не решил.
Надо смотреть чему равен остаток долга и обрабатывать ситуацию, когда он маленький, а не выплачивать сразу же 5000 вот в этом месте: ... + $servicePayment - $payOut;
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
Ответ во втором банке должен быть около 61270.
Посмотри ошибки внизу, их надо исправить.
> PHP Warning: Missing argument 3 for credit(), called in /home/5LpEvn/prog.php on line 23 and defined in /home/5LpEvn/prog.php on line 5
Ты передал меньше аргументов в функцию чем требуется.
> PHP Notice: Undefined variable: fee in /home/5LpEvn/prog.php on line 6
Обращение к несуществующей (потому что ты ее не передал) переменной.
> \tif ($creditBalance < 0) {
> $paymentTotal = $paymentTotal - $creditBalance;
Это явно неправильно. Ведь если ты вычитаешь отрицательное число то paymentTotal становится больше. ну например:
5000 - (-1000) = 6000
Арифметику школьную забыл?
Решил ли ты задачу про айфон, с одним банком? Я вижу что не решил.
Надо смотреть чему равен остаток долга и обрабатывать ситуацию, когда он маленький, а не выплачивать сразу же 5000 вот в этом месте: ... + $servicePayment - $payOut;
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
Ответ во втором банке должен быть около 61270.
> member emp.Tugriki = emp.Compute (500, 400, 200, 800, 1.5)
> member emp.Koffee = emp.Compute (20, 15, 5, 50, 2.0)
это не очень дальновидный подход, что ты пытаешься вычислять кофе/тугрики/деньги по одной схеме так как нет никаких гарантий что формула общая. И понимание кода усложняется. Лучше для каждого ресурса сделать свой метод подсчета.
> type employee =
> ...
> | Boss of employee
Есть защита от Boss of Boss of Boss of Manager ?
Мне кажется, босс это не тип, а флаг так как мы можем назначать/разжаловать из него. Как ты это собрался делать?
Тут нужен именно объект (или структура или что там есть для этого) со свойствами, свойства это ранг и флаг босса. Более того, если ты хочешь писать хороший код то стоит предусмотреть возможность добавлять новые свойства (вдруг мы введем премию за выслугу лет например).
Представлять инженера как обертку над интом на мой взгляд неверно.
> static member (*) (n : int, emp : employee) = List.replicate n emp
Что за странная конструкция? Ручное копирование методов? У вас там прототипов или наследования или каких-нибудь type classes нет что ли?
Можно ли в твоем варианте добавлять профессии не трогая исходный код? С наследованием и ООП можно.
> type department =
> | Buys of employee list
На мой взгляд департамент это один тип, а название просто его свойство. А то в твоем варианте нельзя добавлять департаменты не трогая исходный код.
> ((sprintf "%A" dept)
Костыль же? Можно русское название с пробелами сделать департаменту?
Вывод данных таблицей хорошо бы отделить и вынести в отдельный универсальный модуль или как там у вас это называется.
Также, для тебя есть дополнительное задание (на самом деле я всем его даю), чтобы ты продемонстрировал гибкость языка и расширяемость твоего кода на нем:
### Антикризисные меры
Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
> member emp.Tugriki = emp.Compute (500, 400, 200, 800, 1.5)
> member emp.Koffee = emp.Compute (20, 15, 5, 50, 2.0)
это не очень дальновидный подход, что ты пытаешься вычислять кофе/тугрики/деньги по одной схеме так как нет никаких гарантий что формула общая. И понимание кода усложняется. Лучше для каждого ресурса сделать свой метод подсчета.
> type employee =
> ...
> | Boss of employee
Есть защита от Boss of Boss of Boss of Manager ?
Мне кажется, босс это не тип, а флаг так как мы можем назначать/разжаловать из него. Как ты это собрался делать?
Тут нужен именно объект (или структура или что там есть для этого) со свойствами, свойства это ранг и флаг босса. Более того, если ты хочешь писать хороший код то стоит предусмотреть возможность добавлять новые свойства (вдруг мы введем премию за выслугу лет например).
Представлять инженера как обертку над интом на мой взгляд неверно.
> static member (*) (n : int, emp : employee) = List.replicate n emp
Что за странная конструкция? Ручное копирование методов? У вас там прототипов или наследования или каких-нибудь type classes нет что ли?
Можно ли в твоем варианте добавлять профессии не трогая исходный код? С наследованием и ООП можно.
> type department =
> | Buys of employee list
На мой взгляд департамент это один тип, а название просто его свойство. А то в твоем варианте нельзя добавлять департаменты не трогая исходный код.
> ((sprintf "%A" dept)
Костыль же? Можно русское название с пробелами сделать департаменту?
Вывод данных таблицей хорошо бы отделить и вынести в отдельный универсальный модуль или как там у вас это называется.
Также, для тебя есть дополнительное задание (на самом деле я всем его даю), чтобы ты продемонстрировал гибкость языка и расширяемость твоего кода на нем:
### Антикризисные меры
Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».
Пока ты решал задачу по выводу отчета о сотрудниках и департаментах, разразился мировой экономический кризис. Доходы компании начали снижаться, и совет директоров поставил перед руководством задачу принять меры. Менеджеры 3-го ранга, блестящие выпускники топовых экономических вузов столицы, быстро смогли разработать три альтернативных антикризисных решения:
1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.
2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)
3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.
Совет директоров в затруднении: какой путь выбрать? Помоги им с этим, распечатав прогноз по потреблению и расходам (аналогичный тому что требуется в задаче) после принятия каждой из мер.
Два дня это если в перерыве между написанием кода смотреть аниме. Два дня это же минимум 16 часов, за которые можно гору перевернуть, не то что файлообменник сделать.
>>513414
Надо писать качественный понятный самодокументирующий код используя распространенные библиотеки и фреймворки.
>>513427
Иода
> implode($wordsInSentence, ' ');
разделитель идет первым, смотри мануал
> if (!preg_match("/;/u", $sign))
Не пропускай фигурные скобки, это либо ведет к ошибкам и ухудшению читаемости, либо кому-то придется их ставить за тебя при модификации кода.
Если у тебя есть код
if (условие) {
50 строк
} else {
2 строки
}
То его надо попробовать перевернуть, чтобы было
if (не выполняется условие) {
2 строки
} else {
50 строк
}
То есть лучше короткую ветку сделать первой.
А так, вообще, неплохо сделано, все работает.
Калькулятор
> \tcase '+': $result += (float)$number; break;
Принято писать это в 3 строки, да еще и с отступом. Я понимаю что так нагляднее но не стоит от стандарта оформления ради одног ослучая отступать.
А так, хорошо, все работает.
Два дня это если в перерыве между написанием кода смотреть аниме. Два дня это же минимум 16 часов, за которые можно гору перевернуть, не то что файлообменник сделать.
>>513414
Надо писать качественный понятный самодокументирующий код используя распространенные библиотеки и фреймворки.
>>513427
Иода
> implode($wordsInSentence, ' ');
разделитель идет первым, смотри мануал
> if (!preg_match("/;/u", $sign))
Не пропускай фигурные скобки, это либо ведет к ошибкам и ухудшению читаемости, либо кому-то придется их ставить за тебя при модификации кода.
Если у тебя есть код
if (условие) {
50 строк
} else {
2 строки
}
То его надо попробовать перевернуть, чтобы было
if (не выполняется условие) {
2 строки
} else {
50 строк
}
То есть лучше короткую ветку сделать первой.
А так, вообще, неплохо сделано, все работает.
Калькулятор
> \tcase '+': $result += (float)$number; break;
Принято писать это в 3 строки, да еще и с отступом. Я понимаю что так нагляднее но не стоит от стандарта оформления ради одног ослучая отступать.
А так, хорошо, все работает.
Ты наверно имел в виду процедурный код, функциональный это когда функции оперируют функциями, как на Хаскелле.
>>513512
Смотри лог ошибок, исправляй их.
>>513516
Это устаревшая функция, не используй ее, используй добавление автозагрузчика через spl_autoload_register. Статья: http://habrahabr.ru/post/136761/
> Как эта функция определяет какой класс надо подключить? И как она вообще его находит?
Когда ты в коде обращаешься к несуществующему классу, например:
$a = new MyClass;
MyClass::doSomething();
if (class_exists('MyClass')) {
PHP прежде чем выдать ошибку что класс не существует, вызывает зарегистрированные функции-автозагрузчики передавая им имя класса. Если одна из них подключит файл с классом то выполнение продолжится, если нет то будет ошибка.
> И как она вообще его находит?
Функция получает на вход имя класса и должна как-то определить в каком файле он находится (как именно решаешь ты). Можно например назвать файлы точно так же как и классы, добавляя в конец '.php': MyClass -> MyClass.php
Есть готовый стандарт на эту тему — PSR-4 (хотя он может быть немного сложен, но вся суть в том что имя класса и неймспейсов должно соответсвовать пути к файлу с этим классом).
Если ты будешь называть свои классы в соответствие с PSR-4 то сможешь использовать готовые автозагрузчики, например встроенный в композер.
Ты наверно имел в виду процедурный код, функциональный это когда функции оперируют функциями, как на Хаскелле.
>>513512
Смотри лог ошибок, исправляй их.
>>513516
Это устаревшая функция, не используй ее, используй добавление автозагрузчика через spl_autoload_register. Статья: http://habrahabr.ru/post/136761/
> Как эта функция определяет какой класс надо подключить? И как она вообще его находит?
Когда ты в коде обращаешься к несуществующему классу, например:
$a = new MyClass;
MyClass::doSomething();
if (class_exists('MyClass')) {
PHP прежде чем выдать ошибку что класс не существует, вызывает зарегистрированные функции-автозагрузчики передавая им имя класса. Если одна из них подключит файл с классом то выполнение продолжится, если нет то будет ошибка.
> И как она вообще его находит?
Функция получает на вход имя класса и должна как-то определить в каком файле он находится (как именно решаешь ты). Можно например назвать файлы точно так же как и классы, добавляя в конец '.php': MyClass -> MyClass.php
Есть готовый стандарт на эту тему — PSR-4 (хотя он может быть немного сложен, но вся суть в том что имя класса и неймспейсов должно соответсвовать пути к файлу с этим классом).
Если ты будешь называть свои классы в соответствие с PSR-4 то сможешь использовать готовые автозагрузчики, например встроенный в композер.
Разберись почему, смотри лог ошибок (если CMS отключает логгирование меняя error_reporting то пошли разработчикам нехороших пожеданий и включи). Можешь для удобства также включить display_errors (только не в коде, чтобы на продакшене ошиьки не вываливались на экран).
С путями, смотри какие пути выводятся и откуда они формируются, может какую настройку поменять надо.
Натыкай var_dump или смотри значения переменных отладчиком.
Что ты как маленький.
>>513525
Это не удаление все сессии а только замена значения поля admins на пустую строку.
Но сессии все равно удаляются если к ней 20-30 минут не обращаться.
> $common->re
Это 2 примера как не надо называть переменные и методы. Хорошие дети, не делайте так.
>>513530
include_path это список папок в которых ищется файл если в include/require указан относительный (не идущий от корня диска) путь. читай мануал:
http://php.net/manual/ru/function.require.php
http://php.net/manual/ru/function.set-include-path.php
http://php.net/manual/ru/ini.core.php#ini.include-path
> И как она помогает при аутолоаде, у меня выбивает ошибку.
Разберись почему ошибка. Сдампь имя переданного в автозагрузчик класса и какой файл он пытается подулючить и проанализируй что идет не так.
>>513536
Плохой совет. Анон должен сначала научиться писать автозагрузчики а потом брать готовый. Иначе ничему не научится.
Разберись почему, смотри лог ошибок (если CMS отключает логгирование меняя error_reporting то пошли разработчикам нехороших пожеданий и включи). Можешь для удобства также включить display_errors (только не в коде, чтобы на продакшене ошиьки не вываливались на экран).
С путями, смотри какие пути выводятся и откуда они формируются, может какую настройку поменять надо.
Натыкай var_dump или смотри значения переменных отладчиком.
Что ты как маленький.
>>513525
Это не удаление все сессии а только замена значения поля admins на пустую строку.
Но сессии все равно удаляются если к ней 20-30 минут не обращаться.
> $common->re
Это 2 примера как не надо называть переменные и методы. Хорошие дети, не делайте так.
>>513530
include_path это список папок в которых ищется файл если в include/require указан относительный (не идущий от корня диска) путь. читай мануал:
http://php.net/manual/ru/function.require.php
http://php.net/manual/ru/function.set-include-path.php
http://php.net/manual/ru/ini.core.php#ini.include-path
> И как она помогает при аутолоаде, у меня выбивает ошибку.
Разберись почему ошибка. Сдампь имя переданного в автозагрузчик класса и какой файл он пытается подулючить и проанализируй что идет не так.
>>513536
Плохой совет. Анон должен сначала научиться писать автозагрузчики а потом брать готовый. Иначе ничему не научится.
У вас уже готовые решения есть? Пора видимо условия задач чуть поменять для выявления списывальщиков.
>>513568
Не ругайся.
>>513583
кодеакадеми очень-очень базовый уровень, скорее просто ознакомление с языком. Решай наши задачки (все подряд) чтобы продвинуться дальше.
>>513585
Зачем писать свою CMS? Ты в своем уме? Хочешь платить за то что можно взять готовое? И при этом получить результат худшего качества?
Ты хлеб тоже сам выращиваешь и печешь или в магазине покупаешь?
>>513586
Для этого есть сотни готовых CMS. В 800 строк ты нормальный магазин не уложишь. Я думаю в 800 строк тебе сделают только страничку «о нас».
>>513595
Это вряд ли получится. Все равно надо будет что-то менять.
>>513598
Да, как вариант. Но на хостингах обычно дают пхпмайадмин и можно грузить дамп сразу в него.
Закачивать лучше гзипнутый файл, быстрее будет.
Я бы по scp скпировал и закачал в mysql, там можно даже сделать это не сохраняя на диск.
>>513606
Мне кажется за 2000 в месяц (с нынешним то курсом!) можно несколько натягивателей шаблонов на фрилансе найти. Ой, кажется я сломал твой хитрый план.
У вас уже готовые решения есть? Пора видимо условия задач чуть поменять для выявления списывальщиков.
>>513568
Не ругайся.
>>513583
кодеакадеми очень-очень базовый уровень, скорее просто ознакомление с языком. Решай наши задачки (все подряд) чтобы продвинуться дальше.
>>513585
Зачем писать свою CMS? Ты в своем уме? Хочешь платить за то что можно взять готовое? И при этом получить результат худшего качества?
Ты хлеб тоже сам выращиваешь и печешь или в магазине покупаешь?
>>513586
Для этого есть сотни готовых CMS. В 800 строк ты нормальный магазин не уложишь. Я думаю в 800 строк тебе сделают только страничку «о нас».
>>513595
Это вряд ли получится. Все равно надо будет что-то менять.
>>513598
Да, как вариант. Но на хостингах обычно дают пхпмайадмин и можно грузить дамп сразу в него.
Закачивать лучше гзипнутый файл, быстрее будет.
Я бы по scp скпировал и закачал в mysql, там можно даже сделать это не сохраняя на диск.
>>513606
Мне кажется за 2000 в месяц (с нынешним то курсом!) можно несколько натягивателей шаблонов на фрилансе найти. Ой, кажется я сломал твой хитрый план.
>при попытке зайти на другие страницы сайта браузер их загружает
Я имел ввиду браузер их СКАЧИВАЕТ как текстовые файлы
> $array[$i] = $letter;
для добавления элемента в конец лучше писать просто $letters[] = ...
Название array не годится, оно ничего не говорит.
> $letter = mb_substr($text, $i, 1);
> $array[$i] = $letter;
Это лучше писать в 1 строку без лишней переменной.
> for ($i=$letters; $i > -1 ; $i--) {
> $comparisson = $comparisson . $array[$i];
Есть функции array_reverse и implode, цикл не нужен, погугли мануал.
Кстати для разбиения на буквы тоже есть хак с preg_split, где-то в учебнике в главе про строки описан.
Алгоритм правильный.
> $lenght-1-$i
Можно писать просто -$i - 1, отрицательные числа отситываются с конца строки.
Алгоритм верный.
> задача про айпад в кредит;
> for($i = 0; $credit > 0; $i++){
Если ты не используешь $i то можно ее не писать:
for( ; $credit > 0; ){
А можно вообще заменить это на цикл «повторять пока»:
while ($credit > 0) {
...
}
Мануал http://php.net/manual/ru/control-structures.while.php
> $mountPercent = round(($credit + $comission) * $percent/100, 2);
> $credit = $credit + $mountPercent + $comission;
Можно наверно упростить, умножая долг на (100 + процент) / 100
> $totalPay = $totalPay + $mountPay;
Тут можно использовать +=
А так, решено правильно.
> $array[$i] = $letter;
для добавления элемента в конец лучше писать просто $letters[] = ...
Название array не годится, оно ничего не говорит.
> $letter = mb_substr($text, $i, 1);
> $array[$i] = $letter;
Это лучше писать в 1 строку без лишней переменной.
> for ($i=$letters; $i > -1 ; $i--) {
> $comparisson = $comparisson . $array[$i];
Есть функции array_reverse и implode, цикл не нужен, погугли мануал.
Кстати для разбиения на буквы тоже есть хак с preg_split, где-то в учебнике в главе про строки описан.
Алгоритм правильный.
> $lenght-1-$i
Можно писать просто -$i - 1, отрицательные числа отситываются с конца строки.
Алгоритм верный.
> задача про айпад в кредит;
> for($i = 0; $credit > 0; $i++){
Если ты не используешь $i то можно ее не писать:
for( ; $credit > 0; ){
А можно вообще заменить это на цикл «повторять пока»:
while ($credit > 0) {
...
}
Мануал http://php.net/manual/ru/control-structures.while.php
> $mountPercent = round(($credit + $comission) * $percent/100, 2);
> $credit = $credit + $mountPercent + $comission;
Можно наверно упростить, умножая долг на (100 + процент) / 100
> $totalPay = $totalPay + $mountPay;
Тут можно использовать +=
А так, решено правильно.
> первая задача из урока про регулярные выражения
Регулярка слишком сложная, надо сдеать проще, по принципу «10 цифр и любое число дефисов/пробелов/скобко между ними»
Также задачу про номера телефонов надо проверить на большом числе телефонов, чтобы убедиться что твой код правильный. Но руками подставлять номера — долго и скучно. Пусть работает робот, а не человек!
Для этого давай добавим в программу тесты, чтобы сразу было видно, верно все работает или нет. Сделай 2 списка номеров (правильные и нет), добавь их в программу и напиши цикл, который их по очереди прогоняет через регулярку и проверяет что они определяются как надо (если нет — надо вывести какой именно номер не распознается правильно).
Вот список номеров:
Правильные: array('84951234567', '+74951234567', '8-495-1-234-567', ' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67', '8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567', '8 ( 999 ) 1234567', '8 999 123 4567');
Неправильные: array('02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', // неверный код страны
'+8 234 5678901', // либо 8 либо +7
'7 234 5678901' // нет +
);
По второй задаче:
> Как я думаю - проверку ошибок, чтобы выводить с куском текста, надо делать через preg_match
preg_match ищет только первое совпадение, а тебе нужны все и значит функция preg_match_all которая где-то в уроке в конце описана.
Не ОП, а кто-то другой упоминал книгу Олифера:
Олифер В.Г., Олифер Н.А. "Компьютерные сети. Принципы, технологии, протоколы"
По моему я тоже по ней учился.
Годная книга? Или есть что более понятное? Для саморазвития решил вникнуть в тему работы сетей
Мне интересно, на кого они рассчитаны. на тех кто неспособен просто прочесть или пролистать документацию?
Я вообще негативно отношусь к видеоурокам. зачем они нужны? Маиериал в виде текста и картинок по моему воспринимается лучше чем на слух.
Зачем это? Вы не можете сами догадаться что открыть и что нажать? На собеседовании и на работе же вам все равно придется своей головой думать.
отлично, спасибо
Я вот например узнал что хотят сделать типизированные энумы.
А что такого то собственно? В видеоуроках можно гораздо все подробнее рассказать и буквально показать на пальцах то, как оно все работает. В текстовом виде этого сделать невозможно, в виду его ограниченности.
А если есть возможность изучить какую-то тему более подробно, то почему бы ей не воспользоваться?
>Зачем писать свою CMS? Ты в своем уме?
Допустим у заказчика очень специфичные требования к Админке. Плюс надо же это все с шаблонами и теплейтами связать.
хуяси.
$numrows = $db->n($result);
\t\t\tif($numrows>0) {
\t\t\t\t$row = mysql_fetch_array($result);
\t\t\t\techo $row['text'];
echo $row['name_comments'];
echo $row['text_comments'];
\t\t\t}
Такое запрос выведет ли циклом таблицу с внешними ключами, т.е. инфу из двух таблиц (статья и комменты)? Циклом, это важно. Родительская таблица book, дочерняя book. ключи: id = id book, id comments = id_comments.
>> if (!isset($this->$class)) {
>Вот это неправильно. Завязывай с динамиечскими свойствами, объект это не массив чтобы в него их добавлять (а если тебе нужны динамические свойства, используй лучше массив).
А что плохого в динамических свойствах? И в каких случаях они уместны?
код забыл
SELECT `vedma_book` .*, `comments` . `name_comments` . `text_comments` FROM `vedma_book` INNER JOIN `comments` ON `vedma_book`.`id` = '".$id."=`comments`.`id`
echo "<form method='post' action='".$path."index.php'><input type='text' name='name_comments'/><input type='text' name='text_comments'><button type='submit'>Оставить комментарий</button></form>";
\t\t\t$name_comments=$_POST['name_comments'];
\t\t\t$text_comments=$_POST['text_comments'];
\t\t\t$result2 = $db->q("INSERT INTO `comments` VALUES(``, ,``,`$name_comments`, `$text_comments`) WHERE `id`=".$id."");
\t\t$ar = array_keys($array);
\t\t$coun = count($array);
\t\tfor($i=0; $i<$coun; $i++) {
\t\t\tif(strpos($doc,'<!-- IF '.$ar[$i].' -->')) {
\t\t\t\tif($array[$ar[$i]]) {
\t\t\t\t\t$doc = preg_replace('#\<!-- IF '.$ar[$i].' -->(.?)\<!-- ENDIF -->#isu', '\\1', $doc);
\t\t\t\t} else {
\t\t\t\t\t$doc = preg_replace('#\<!-- IF '.$ar[$i].' -->(.?)\<!-- ENDIF -->#isu', '', $doc);
\t\t\t\t}
\t\t\t}
\t\t\tif(strpos($doc,'<!-- IF !'.$ar[$i].' -->')) {
\t\t\t\tif($array[$ar[$i]]) {
\t\t\t\t\t$doc = preg_replace('#\<!-- IF !'.$ar[$i].' -->(.?)\<!-- ENDIF -->#isu', '', $doc);
\t\t\t\t} else {
\t\t\t\t\t$doc = preg_replace('#\<!-- IF !'.$ar[$i].' -->(.?)\<!-- ENDIF -->#isu', '\\1', $doc);
\t\t\t\t}
\t\t\t}
\t\t}
\t\treturn $doc;
\t}
\tfunction style_tpl($tpl, $array) {
\t\tglobal $style;
\t\t$doc1 = fopen('templates/tpl/'.$tpl, "r");
\t\t$doc = fread($doc1, filesize('templates/tpl/'.$tpl));
\t\tfclose($doc1);
\t\t$doc = $style->style_if($doc, $array);
\t\t$doc = $style->style_begin($doc, $array);
\t\t$doc = $style->style_for($doc, $array);
\t\t$doc = $style->style_const($doc, $array);
\t\treturn $doc;
\t}
берет ли она всю инфу из tpl или какую-то определенную хуйню, минуя дописанные дивы?
Исправил загрузку через имя ссылки, все оказалось в разы проще чем я думал в самом начале
Сделал загрузку mediaInfo через json_array в Доктрине, это походу не совсем то что ты имел в виду ОП, но я что-то не разобрался как нужно было сделать правильно
Или достаточно просто повесить $_COOKIE['login'] = '1'?
Может ли "злоумышленник" подделать куки и записать туда значение?
Или лучше сохранять в куки хешированный пароль, а потом сверять с базой каждый раз при запросе?
Да, походу нужно сохранять в куки хеш и id.
Вкачусь в тред дебилов.
>$_COOKIE['login'] = '1
Слишком толсто.
Используй фреймворк с реализованной из коробки авторизацией и аутентификацией, там будет таблица сессий, нормальная шифровка паролей, етс... Или ищи standalone php-библиотеки качественные.
Выкатывайся обратно.
Это учебный тред, мы тут учимся пониманию, как реализуется тот или иной функционал, а не используем обезьяньи готовые решения.
Если ты используешь фреймворк, но не понимаешь как он работает, то ты макака, а не программист.
>https://github.com/slimphp/Slim/blob/2.x/Slim/Helper/Set.php
>https://github.com/silexphp/Pimple/blob/master/src/Pimple/Container.php
Код контейнера в Slim для меня выглядит понятней. Непонятно только, зачем эта функция: https://github.com/slimphp/Slim/blob/2.x/Slim/Helper/Set.php#L62
А мой di-контейнер теперь выглядит так:
https://github.com/blackberryJam/abiturients/blob/master/app/classes/Container.php
Не такой гибкий, как в Slim и Silex.
Прохожу курсы htmlacademy по html и css, потом уже думаю за js взяться, и только потом за php.
Как вы мотивируетесь учиться? Я успешно прошел 5 курсов основ, вроде все просто, все понял, все запомнил, пора бы идти дальше, но что-то никак. Сажусь за комп, чтобы учиться, но какой-то стопор нападает и ничего в голову не лезет. Заставляй, не заставляй, не помогает. Как замотивироваться? Сиже у мамки на шее, хочу слезть, но видимо пока в зоне комфорта нахожусь, мозг ничего не хочет менять. Что делать?
Очевидно выйти из зоны комфорта.
Устройся на пару месяцев работать в какое-нибудь гнусное место, типа продавца в фокстроте, офигей от осознания, что если не будешь учиться, то проживешь так всю жизнь.
Мотивация появится, гарантирую.
>меня отовсюду гонят ссыными тряпками
Кажется, я понимаю почему.
Нет, для саморазвития лучше "Основы компьютерных сетей" тех же авторов, семейства Олифер.
Там все излагается гораздо более кратко и доступно. "Компьютерные сети" для гиков, "Основы" для нубов. Сами аффтары тралят в предисловии, говорят мол для ниасиляторов выпускаем лайт-версию, пикрелейтед.
Лол, описал мою стори 1в1, толко я с тян живу в ее квартире в ДС и она меня обеспечивает, я только изредка подрабатываю на всяки-разных шабашках. Тоже грозится выгнать, если работу не найду. Тоже по htmlacademy занимаюсь, думаю куда попробовать стажером-верстальщиком за еду на первое время попробовать устроится. Но пока везде отказывают, даже контентщиком не хотят брать. От этого мотивация совсем испаряется, думаю появится, когда тян меня на мороз выкинет.
Я уже набираю не глядя на клавиатуру, запомнил почти все хоткеи саблайма, но дурацкие стрелочки все портят, приходится отвлекаться и смотреть на клаву.
У меня еще ноут неудобный, у него стрелки как на пике.
Слышал, что в саблайме есть какой-то Vintage Mode, где можно переключаться в режим вставки, как в линуксовых редакторах. http://habrahabr.ru/post/193176/
Как оно, долго осваивается? ОП, я знаю ты кодишь в саблайме. Пользуешься этой хренью, или тыкаешь на стрелочки? Может там есть другие настройки, не хочу я еще вим учить в придачу (все равно придется, но пока рано я считаю).
Ебать ты лох.
Тян 8 из 10, правда сисек почти нет и от хламидий лечится.
Тем временем завершил 4-ый курс на htmlacademy. Перехожу наконец к таблицам, надеюсь наконец разберусь почему верстка div'ами лучше табличной. Помню в школе все таблицами хуярил и был доволен.
Ну это уж совсем зашквар, тем более я очень херово пишу. Не умею свои мысли на бумаге хорошо выражать и все тут.
Бухгалтером. Хламидии от бывшего остались. Вместе переживаем. Зато трахаться не нужно, не очень это люблю.
Добра, за наводку. Искал там, но не нашел. Перекатываюсь.
научите меня программировать на компьютере, позязя =)))
Сперва асечку писечку :3333
По одной ссылке от опа нечитабельные регекспы по 3 строки http://habrahabr.ru/post/55820/
По второй ссылке аффтар говорит "ни парьтесь))" и предлагает использовать /@/ либо /.+@.+/, то есть лишь бы была собачка.
http://habrahabr.ru/post/175375/
Самым правильным кажется действительно высылать юзеру письмо со ссылкой, перейдя по которой его данные будут подтверждены.
Собачка только и есть теперь. Сейчас кучу доменов же новых ввели, плюс многоязычные url. Если как в хабрапосте делать, часть юзеров тупо зарегаться не сможет.
Так под /.+@.+/ подойдет любая галиматья, в том числе куча собачек 'abc@@@@hello.world'
Ладно, пока просто исключу пробелы и лишние собачки
$regExp = '/^[^@\s]+@[^@\s]+\.[^@\s]+$/ui';
Множественные собачки тоже разрешены http://tools.ietf.org/html/rfc5322#section-3.2.1
Валидный емайл может быть типа "vanka@erohin"@быдло.рф
Do while . Сначала делай, потом думай
Пробелы тоже разрешены "vanka@erohin ebashit ebalo"@быдло.рф
Где постоянно крутиться будет и неизвестно сколько циклов, юзаю while.
Где заранее известно, сколько циклов, юзаю for.
Сиськи с сапом или иди нахуй.
И я тоже Тян, хочу уметь в программирование, ч же не та. Научите ^_^
1. infomania.cc/viewtopic.php?t=3596
2. infomania.cc/viewtopic.php?t=3597
3. infomania.cc/viewtopic.php?t=3598
на nnm-club есть, разных годов, разного качества
И четвертый курс кстати отстой. Там намешано бессвязной информации, все подряд, лишь бы набрать время: паттерны, отражения, curl, обзор фреймворков и т.д.
Ну там и рассчитано на обзор видимо, так как все это подробно разбирать оч долго. Предполагается, что ты дальше сам
У меня есть 2: старый и новый, но оба не полностью
Освоить какой-нибудь фреймворк, можно сразу с symfony, всё остальное будет проще даваться, потом понять что такое REST и как должен выглядеть адеквакватный REST, чтобы фронтендер не блювал при работе с ним. Всё, ты бэкенд-пхп макака со знаниями чуть выше нулевых.
Закрыть все вкладки справа
Закрыть остальные вкладки
Если навести мышь на эти пункты, то упомянутые в них заголовки вкладок наинают мигать. Мигать! Кому-то в гугле было не лень добавить обработчик события наведения мыши на этот пункт и написать код отвечающий за мигание вкладок.
Мне нравится когда люди подходят к разработке программ так тщательно и внимательно. Это не руби и нодошкольники, которые лепят код который хорошо если хоть иногда работает.
Жаль правда, все это делается не ради того чтобы сделать лучший браузер, а ради усиления монополии гугла и привязки людей к его сервисам.
Пиздец рано мне еще на фриланс вкатываться. Поделаю лучше задачки у ОПа, напишу свою цмску..
Я на ксубунту: мигает, если присмотреться. Но не сразу, и еле заметно.
Ерунда по-моему, но оп имел ввиду дотошность программистов, которые уделили внимание даже такой мелочи.
Фреймворки это код, готовый для повторного использования.
Например на каждом сайте есть формы регистрации, вывод записей, сохранение в базу данных и так далее.
Чтобы не писать каждый раз одно и то же, подобный повторяющийся код сохраняют в отдельные пакеты, и затем используют эти готовые классы, вместо того чтобы писать с нуля.
Cms это программки, которые генерируют однотипные сайты. Выбираешь галочками или из выпадающего списка опции и нажимаешь "создать". И "оно само" тебе делает рабочий сайт.
Cms не любят по причине того, что они заточены именно под какие-то стандартные сайты, и не всегда удобно что-то изменить, дописать.
И они плохо развиваются, используют устаревшие технологии.
как же я ненавижу цмс, проще с нуля админку самому написать.
Атвичяю. У меня на бубунте мигает.
ДЕЦ(6,3) - 3 знака после запятой, 3 знака до запятой. Поэтому всего 6.
ДЕЦ(20,6) - 14 знаков до запятой, 6 знаков после запятой. Всего 20.
Считается, просто на группы делится по ней. В ДЕЦ(20,6) - хранится 9 знаков в 4х байтах, 5 знаков в 3х байтах (это все до запятой) и 6 знаков в 3х байтах (часть после запятой).
Спасибо.
Но другого-то у нас нет, так что попью чаю и сяду исправлять.
Нет, с чего бы это? Я советую не гадать, а почитать про джойны в любом учебнике по SQL или в туториале: http://jtest.ru/bazyi-dannyix/sql-dlya-nachinayushhix-chast-3.html
>>513742
да почти никогда не уместны. Объект тем и отличатся что у него заранее известный набор свойств. Если тебе надо добавлять свойства то бери массив а не объект.
Динамические свойства — верный путь в быдлокодеры.
>>513744
Это долго объяснять. Тебе нужна библиотека для скачивания страницы и библиотека для разбора DOM.
>>513752
У тебя код просит улучшения:
— не подставляй переменные в запрос, используй плейсхолдеры
— не смешивай логику по выборке данных и HTMl код в одном файле
— не используй echo для вывода HTML
— научись правильно работать с формами, например у меня есть урок по теме https://github.com/codedokode/pasta/blob/master/forms.md
Тебе рановато пока такие вещи писать, я бы советовал начать с нашего задания про список студентов. Там подробные комментарии к заданию.
Это самописный шабонизатор — один из лучших способов подложить свинью тем, кто работает с кодом после тебя (ну в данном случае подложили тебе).
>>513775
Правильно сделать свой тип который преобразует данные между объектом класса MediaInfo и строкой с JSON данными. Я же вроде даже давал ссылку на мануал:
http://doctrine-orm.readthedocs.org/en/latest/cookbook/custom-mapping-types.html
У тебя сделано непраивльно. У тебя при загрузке из БД получится не объект MediaInfo а массив или какой-нибудь StdClass (который по сути тот же масссов только без функций для работы с ним).
Также, вот это:
> https://github.com/V3N0m21/Uppu3/blob/master/app/Resource/FileResource.php#L88
Стоит вынести наружу из модели. Это не ее задача, анализировать типы файлов.
папку .idea надо убрать из репозитория и добавить в gitignore
> if ($bytes >= 1073741824)
Это лучше писать как 1024×1024×1024 а то какое-то магиеское число получилось.
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L13
> throw new Exception("File not an image", 1);
В сообщение об ошибке стоит добавлять имя файла, иначе наткнувшись на него в логе ничего не понять.
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L28
> $this->mime = $img['mime'];
getimagesize может вернуть false, надо это проверять
При ресайзе маленькие картинки не увеличиваются? ЧТо-то я не вижу проверки на это.
> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L8
> $config->setQueryCacheImpl(new \Doctrine\Common\Cache\ApcCache());
Стоит сделать проверку на наличие apc и при отсуствии откатываться на файловый кеш
Имена и пароли к базе данных надо вынести в конфиг.
> https://github.com/V3N0m21/Uppu3/blob/master/app/templates/layout.html#L6
> {{ app.request.getRootUri() }}../css/bootstrap.min.css
Что-то это странно. Зачем тут две точки? Мне кажется сразу должен идти путь. Что у тебя выдает getRootUri() ?
Также, чтобы не копипастить стоит поместить этот путь в переменную.
> {% if helper.isPicture(file.extension) == true %}
Можно просто {% if helper.isPicture(file.extension) %}
> https://github.com/V3N0m21/Uppu3/blob/master/app/templates/view.html#L4
> {% if helper.isPicture(file.extension) == true %}
То-то мне эта проверка кажется ненадежной. Лучше бы записывать для файла флаг, есть у него картинка или нет. Ведь тип файла может определиться как картинка, но она окажется нечитаемой.
> https://github.com/V3N0m21/Uppu3/blob/master/files.sql#L31
> `name` varchar(255) DEFAULT NULL,
Почему DEFAULT NULL? МОжно не заполнять это поле?
Код загрузки файла стоит вынести из index.php и модели в какую-нибудь функцию или класс.
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L49
> $message = 'File was successfully uploaded';
переменная никуда не идет
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L74
>$name = FormatHelper::formatDownloadFile($id, $file->getName());
Ты переиспользуешь переменную для другой цели и это запутывает код. Я думал name это то что пришло от пользователя.
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L92
> ->createQuery('SELECT g FROM Uppu3\Resource\FileResource g ORDER BY g.uploaded DESC')
Тут надо добавить setMaxResults для ограничения числа файлов
Кстати для простой выборки без условий можно использовать
$files = $repository->findBy([], ['name' => 'ASC'], ...)
По моему там же и LIMIT можно задать: http://www.doctrine-project.org/api/orm/2.2/class-Doctrine.ORM.EntityRepository.html#_findBy
Вообще, пока неплохо. Сделашь древовидные комментарии? Там для доктрины есть расширение для работы с деревьями, было бы неплохо и с ним разобраться. Вот оно: https://github.com/Atlantic18/DoctrineExtensions
(тебе нужно Tree)
Вот урок про способы хранить древовидные данные в БД: https://gist.github.com/codedokode/10539720
Это самописный шабонизатор — один из лучших способов подложить свинью тем, кто работает с кодом после тебя (ну в данном случае подложили тебе).
>>513775
Правильно сделать свой тип который преобразует данные между объектом класса MediaInfo и строкой с JSON данными. Я же вроде даже давал ссылку на мануал:
http://doctrine-orm.readthedocs.org/en/latest/cookbook/custom-mapping-types.html
У тебя сделано непраивльно. У тебя при загрузке из БД получится не объект MediaInfo а массив или какой-нибудь StdClass (который по сути тот же масссов только без функций для работы с ним).
Также, вот это:
> https://github.com/V3N0m21/Uppu3/blob/master/app/Resource/FileResource.php#L88
Стоит вынести наружу из модели. Это не ее задача, анализировать типы файлов.
папку .idea надо убрать из репозитория и добавить в gitignore
> if ($bytes >= 1073741824)
Это лучше писать как 1024×1024×1024 а то какое-то магиеское число получилось.
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L13
> throw new Exception("File not an image", 1);
В сообщение об ошибке стоит добавлять имя файла, иначе наткнувшись на него в логе ничего не понять.
> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L28
> $this->mime = $img['mime'];
getimagesize может вернуть false, надо это проверять
При ресайзе маленькие картинки не увеличиваются? ЧТо-то я не вижу проверки на это.
> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L8
> $config->setQueryCacheImpl(new \Doctrine\Common\Cache\ApcCache());
Стоит сделать проверку на наличие apc и при отсуствии откатываться на файловый кеш
Имена и пароли к базе данных надо вынести в конфиг.
> https://github.com/V3N0m21/Uppu3/blob/master/app/templates/layout.html#L6
> {{ app.request.getRootUri() }}../css/bootstrap.min.css
Что-то это странно. Зачем тут две точки? Мне кажется сразу должен идти путь. Что у тебя выдает getRootUri() ?
Также, чтобы не копипастить стоит поместить этот путь в переменную.
> {% if helper.isPicture(file.extension) == true %}
Можно просто {% if helper.isPicture(file.extension) %}
> https://github.com/V3N0m21/Uppu3/blob/master/app/templates/view.html#L4
> {% if helper.isPicture(file.extension) == true %}
То-то мне эта проверка кажется ненадежной. Лучше бы записывать для файла флаг, есть у него картинка или нет. Ведь тип файла может определиться как картинка, но она окажется нечитаемой.
> https://github.com/V3N0m21/Uppu3/blob/master/files.sql#L31
> `name` varchar(255) DEFAULT NULL,
Почему DEFAULT NULL? МОжно не заполнять это поле?
Код загрузки файла стоит вынести из index.php и модели в какую-нибудь функцию или класс.
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L49
> $message = 'File was successfully uploaded';
переменная никуда не идет
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L74
>$name = FormatHelper::formatDownloadFile($id, $file->getName());
Ты переиспользуешь переменную для другой цели и это запутывает код. Я думал name это то что пришло от пользователя.
> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L92
> ->createQuery('SELECT g FROM Uppu3\Resource\FileResource g ORDER BY g.uploaded DESC')
Тут надо добавить setMaxResults для ограничения числа файлов
Кстати для простой выборки без условий можно использовать
$files = $repository->findBy([], ['name' => 'ASC'], ...)
По моему там же и LIMIT можно задать: http://www.doctrine-project.org/api/orm/2.2/class-Doctrine.ORM.EntityRepository.html#_findBy
Вообще, пока неплохо. Сделашь древовидные комментарии? Там для доктрины есть расширение для работы с деревьями, было бы неплохо и с ним разобраться. Вот оно: https://github.com/Atlantic18/DoctrineExtensions
(тебе нужно Tree)
Вот урок про способы хранить древовидные данные в БД: https://gist.github.com/codedokode/10539720
> Или достаточно просто повесить $_COOKIE['login'] = '1'?
> Может ли "злоумышленник" подделать куки и записать туда значение?
Куки хранятся в браузере и с ними можно делать все что угодно. Для авторизации обычно либо используют сессию (но она умирает через полчаса неактивности) либо в куках хранят id пользователя + хеш пароля или какой-то длинный токен который не подобрать.
>>513822
> Непонятно только, зачем эта функция
Там класс Set используется не только как DI контейнер, но и для других целей вроде хранения HTTP заголовков.
Судя по комментарию
> Used in subclasses
> like \Slim\Http\Headers.
Она используется чтобы приводить их все к нижнему регистру так как имена заголовков нечувствительные к регистру. Скорее всего класс-наследник хранящий заголовки переопределяет ее, давай-ка глянем:
https://github.com/slimphp/Slim/blob/2.x/Slim/Http/Headers.php#L94
> А мой di-контейнер теперь выглядит так:
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/Container.php#L26
> $this->validator = new Validator($this->abiturientsMapper);
Если вызвать getValidator самой первой то она упадет. Тут должно быть не оьращение к полю а вызов метода.
> Не такой гибкий, как в Slim и Silex.
Ну так у них на все случаи жизни а у тебя только для твоего приложения.
> Или достаточно просто повесить $_COOKIE['login'] = '1'?
> Может ли "злоумышленник" подделать куки и записать туда значение?
Куки хранятся в браузере и с ними можно делать все что угодно. Для авторизации обычно либо используют сессию (но она умирает через полчаса неактивности) либо в куках хранят id пользователя + хеш пароля или какой-то длинный токен который не подобрать.
>>513822
> Непонятно только, зачем эта функция
Там класс Set используется не только как DI контейнер, но и для других целей вроде хранения HTTP заголовков.
Судя по комментарию
> Used in subclasses
> like \Slim\Http\Headers.
Она используется чтобы приводить их все к нижнему регистру так как имена заголовков нечувствительные к регистру. Скорее всего класс-наследник хранящий заголовки переопределяет ее, давай-ка глянем:
https://github.com/slimphp/Slim/blob/2.x/Slim/Http/Headers.php#L94
> А мой di-контейнер теперь выглядит так:
> https://github.com/blackberryJam/abiturients/blob/master/app/classes/Container.php#L26
> $this->validator = new Validator($this->abiturientsMapper);
Если вызвать getValidator самой первой то она упадет. Тут должно быть не оьращение к полю а вызов метода.
> Не такой гибкий, как в Slim и Silex.
Ну так у них на все случаи жизни а у тебя только для твоего приложения.
Не знаю, я не использую, я не хочу изучать древние схемы клавиш с тех времен когда были терминалы-печатающие машинки без стрелок. На моей клавиатуре стрелки нормальные.
> не хочу я еще вим учить в придачу (все равно придется, но пока рано я считаю).
Я не учил и не собираюсь, единственная комбинация клавиш которую я знаю это :q! или как-то так, для выхода.
Режимы это зло с точки зрения юзабилити — вспомни сколько раз ты набирал текст не в той раскладке.
>>513962
Не знаю.
>>514016
Лучше той что проще.
>>514028
> Ладно, пока просто исключу пробелы и лишние собачки
Вполне подойдет
>>514034
Да, там всякие странные комбинации разрешены но мы будем считать что человек опечатался. На практике такой email наверно нигде не заработает.
>>514046
Для разных слуаев разные циклы.
>>514225
То есть ты ленив и не хочешь изучать технологии? я не думаю что это произведет впечатление на работодателя. Людив вузах по 5 лет учатся, а тебе лень несколько месяцев на основы фронтенда потратить?
Никто не будет тебе выделять личного верстальщика.
>>514247
Сразу симфони сложновато. ЛУчше начать с наших задачек а студентов и на файлообменник..
Не знаю, я не использую, я не хочу изучать древние схемы клавиш с тех времен когда были терминалы-печатающие машинки без стрелок. На моей клавиатуре стрелки нормальные.
> не хочу я еще вим учить в придачу (все равно придется, но пока рано я считаю).
Я не учил и не собираюсь, единственная комбинация клавиш которую я знаю это :q! или как-то так, для выхода.
Режимы это зло с точки зрения юзабилити — вспомни сколько раз ты набирал текст не в той раскладке.
>>513962
Не знаю.
>>514016
Лучше той что проще.
>>514028
> Ладно, пока просто исключу пробелы и лишние собачки
Вполне подойдет
>>514034
Да, там всякие странные комбинации разрешены но мы будем считать что человек опечатался. На практике такой email наверно нигде не заработает.
>>514046
Для разных слуаев разные циклы.
>>514225
То есть ты ленив и не хочешь изучать технологии? я не думаю что это произведет впечатление на работодателя. Людив вузах по 5 лет учатся, а тебе лень несколько месяцев на основы фронтенда потратить?
Никто не будет тебе выделять личного верстальщика.
>>514247
Сразу симфони сложновато. ЛУчше начать с наших задачек а студентов и на файлообменник..
Не любят те кто не осилил.
>>514343
Набор готовых классов.
>>514378
Отчего же, популярные фрйемворки типа Юи или Симфони очень гибкие.
>>514394
Флоат это приближенные данные, децимал гарантирует сохранение нужного числа знаков, и испоьзует более точную математику. ПРименяют для денег в основном.
>>514438
Фреймворк для тестов, хипстеры такими вещами не интересуются.
>>514477
Предложи денег в /web и желающие найдутся.
>хипстеры такими вещами не интересуются.
Хипстеры как раз и интересуются. Остальные тесты вручную пишут.
Это не на программирование задачки же. Просто отсев для тех, кто в понтовых физмат вузах учился. Яндексу скорее математики нужны, а не программисты.
Это когда метод принимает объект строго заданного класса? Будет ли следующий пример реализацией этого паттерна:
class FileMapper
{
public function save(File $file){//*}
}
>Объясните лаконично и доступно, в чем суть внедрения зависимости?
Суть в том, что класс, зависящий от другого класса, получает экземпляр этого другого класса извне, а не создаёт его в теле своих методов.
Тут объяснение о ОПа:
>>511406
>> $mapper = new AbiturientsMapper($GLOBALS['pdo']);
>Не, так не годится. Во-первых ты не должен создавать маппер в сервисе (а должен передавать извне), во-вторых не должен использовать GLOBALS.
>
>Лучше сделать так:
>
>$service = new AbiturientService($abiturientMapper, $validator);
>
>Это назвыается Dependency Injection через конструктор. Урок по теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057
>
>Заметь что для контроллеров обычно это не применяют. Обычно контроллер имеет доступ к DI контейнеру и может получить любой сервис из него. Так что, раз уж ты решил нагородить ООП, сделай-ка DI container. Это класс, который создает или (при повторном обращении) возвращает ранее созданные сервисы, он выглядит примерно так:
>
>$mapper = $container->getAbiturientMapper();
>$service = $container->getAbiturientService();
>
>Сами сервисы и мапперы не должны ничего про него знать (иначе код будет запутанным и мы получим service locator), а вот контроллер вполне может иметь к нему доступ. Создавать сам контейнер удобно в bootstrap.php.
>
>Как альтернатива, можно создать контейнер с публичными свойствами и в bootstrap прописать в них мапперы и сервисы, тогда к ним можно обращаться как $container->someMapper. Это работает когда сервисов немного.
>
>В общем код вроде new AbiturientsMapper(...); должен быть только в одном месте. Любой сервис должен быть только в одном экземпляре и не должен создаваться по несколько раз (иначе будет путаница, один экземпляр проставил какое-то поле, а ты вызваешь другой экземпляр где у поля другое значение).
>
>Объясните лаконично и доступно, в чем суть внедрения зависимости?
Суть в том, что класс, зависящий от другого класса, получает экземпляр этого другого класса извне, а не создаёт его в теле своих методов.
Тут объяснение о ОПа:
>>511406
>> $mapper = new AbiturientsMapper($GLOBALS['pdo']);
>Не, так не годится. Во-первых ты не должен создавать маппер в сервисе (а должен передавать извне), во-вторых не должен использовать GLOBALS.
>
>Лучше сделать так:
>
>$service = new AbiturientService($abiturientMapper, $validator);
>
>Это назвыается Dependency Injection через конструктор. Урок по теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057
>
>Заметь что для контроллеров обычно это не применяют. Обычно контроллер имеет доступ к DI контейнеру и может получить любой сервис из него. Так что, раз уж ты решил нагородить ООП, сделай-ка DI container. Это класс, который создает или (при повторном обращении) возвращает ранее созданные сервисы, он выглядит примерно так:
>
>$mapper = $container->getAbiturientMapper();
>$service = $container->getAbiturientService();
>
>Сами сервисы и мапперы не должны ничего про него знать (иначе код будет запутанным и мы получим service locator), а вот контроллер вполне может иметь к нему доступ. Создавать сам контейнер удобно в bootstrap.php.
>
>Как альтернатива, можно создать контейнер с публичными свойствами и в bootstrap прописать в них мапперы и сервисы, тогда к ним можно обращаться как $container->someMapper. Это работает когда сервисов немного.
>
>В общем код вроде new AbiturientsMapper(...); должен быть только в одном месте. Любой сервис должен быть только в одном экземпляре и не должен создаваться по несколько раз (иначе будет путаница, один экземпляр проставил какое-то поле, а ты вызваешь другой экземпляр где у поля другое значение).
>
>класс, зависящий от другого класса, получает экземпляр этого другого класса извне, а не создаёт его в теле своих методов
Это понял.
>можно создать контейнер с публичными свойствами и в bootstrap прописать в них мапперы и сервисы
Тут речь походу о синглтонах, чтобы эти мапперы и сервисы были одним и тем же объектом, а не плодились новые экземпляры, я так понял.
Статью почитаю на досуге, но выглядит тяжеловатой. Неужели нельзя излагать мысли ясно и понятно?
>Урок по теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057
Урок невнятный какой-то, непонятно чем Service Locator лучше Registry, можно и тех и других разных насоздавать.
Нормальный урок, че ты.
Чтобы насоздавать разных Registry, тебе придётся описывать много классов и потом бегать по всему коду и заменять имя на новое везде, где он используется. А в случае с SL создаются именно экземпляры, которые пишутся в переменную, например. Это проще.
Ну и минусы Registry и его отличия от SL описаны в уроке.
Редко почему-то вижу, чтобы его кто-то использовал.
Ну хз, как-то очень непонятно там все автор описывает, неясно где и что он имеет в виду.
Как я понял, единственное отличие, что Registry статический, а SL обычный класс, которому экземпляр надо делать. Ну и чем он тогда лучше? Что там, что там методы писать одинаково. Если нужно, чтобы разные настройки были, у Registry можно массив настроек сделать и вызывать нужную в геттере по индексу, в сеттере так же с индексом ставить.
По минусам вроде все тоже одинаково.
Валидный. / под рукой просто, а к # тянуться надо и shift нажимать, неудобно же.
Я просто собираюсь хранить хеш в базе, поставил бы char, но вдруг понадобится другой хеш, который возвращает скажем строку из 80 символов.
Что будет, если через alter table поменять char(40) на char(80)? Все записи, которые уже есть в базе, добьются пробелами до 80 символов?
Наверное я лучше поставлю varchar, и не будет хлопот.
И расскажите о "миграциях", потому что я слышал что не нужно лезть в базу и править таблицы руками, это нужно делать через эти самые миграции. Что это вообще?
Меняй на varchar(80) и включи ALTER TABLE imyatablici ROW_FORMAT=FIXED;
Тогда по скорости будет как char, а по объему как для 80.
Ты еще битрикс не видел.
Если зазубрить api, то будет легче разобраться.
Во фреймворках тоже кстати придется долго заучивать, как разрабы назвали тот или иной класс, метод, свойство. Но там хоть какая-то логика есть, и все взаимосвязано.
>127.0.0.1 alex.org
Создал конфиг в sites-available (коменты убрал)
><VirtualHost *:80>
> ServerAdmin admin@alex.org
> ServerName alex.org
> ServerAlias www.alex.org
> DocumentRoot /var/www/alex.org/public_html
> ErrorLog ${APACHE_LOG_DIR}/error.log
> CustomLog ${APACHE_LOG_DIR}/access.log combined
></VirtualHost>
Включил сайт a2ensite alex.org.conf, теперь он отображается в sites-enabled
Апач перезапустил.
И тут проблема:
Перехожу на alex.org, меня кидает в дефолтный сайт (/var/www/html/index.html). Я хочу попадать на /var/www/alex.org/public_html/index.html Что я упустил? Пол-дня пытаюсь разобраться.
Нет, платина это "чо у меня денвир выдает кракозябры?"
Попробуй в настройках хоста
<Directory /var/www/alex.org/public_html>
Require all granted
</Directory>
Хз, что за sites-available, ставь через httpd-vhosts.conf в apache/conf/extra как все люди.
const MY_CONST = 'hello';
echo MY_CONST[1];
Я уже понял, что нельзя, он мне пишет в лог unexpected [ или unexpected {
Но может какой-нибудь оп скажет что-то умное по этому поводу, почему так происходит. Вроде бы в константе тоже строка, с чем это связано?
У меня класс вспомогательный, у него только статичные методы и константы.
Мне эту переменную видимо придется жоско зашить в статичный метод, внутри которого она используется. А если эта строка мне понадобится в других методах?
Хм, я тогда сделаю статичный метод, который тупо возвращает эту строку. Что поделать.
>>514633
>>514638
Спасибо конечно, я решил проблему иначе, но это вообще пушка.
http://stackoverflow.com/questions/23713061/virtualhost-always-returns-default-host-with-apache-on-ubuntu-14-04
Первый коммент с 13 плюсами. Меня наебал сам апач. Мне еще предстоят подобные подводные камни? Пол дня въебал впустую изза того что там нет нормального сообщения об ошибке.
Я всегда использую service apache2 restart, а не reload.
restart перезапускает сервер с нуля, то есть stop + start.
reload перезагружает только какие-то там конфиги, не факт что те что надо.
DI это когда мы передаем классу A класс B снаружи и тем самым делаем эти классы менее спутанными. Обязательные зависимости обычно внедряются через конструктор, необязательные через сеттеры.
> Будет ли следующий пример реализацией этого паттерна:
Нет так как File это не сервис от которого зависит FileMapper. Это объект, с которым работает метод save.
А вот объект PDO в FileMapper стоит передавать именно через конструктор. Это позволяет внешнему коду решать какой именно объект какого класса будет использовать FileMapper для выполнения запросов.
>>514561
>Тут речь походу о синглтонах,
Не совсем то. Анон говорит про DI container то есть класс который содержит в себе экземпляры сервисов (должны же они где-то храниться).
>>514568
Registry это не очень хороший паттерн, так как он не обсепечивает DI. Он приведен в пример только чтобы показать что такой паттерн есть и может где-то используется.
Registry это когда в начале программы мы делаем:
Registry::set('serviceA', new ServiceA);
а в классе B делаем
$serviceA = Registry::get('serviceA');
Тут как видишь полноценной DI нет, мы не можем явно классу B передать экземпляр serviceA, он сам его берет из реестра.
Вот описание: http://design-pattern.ru/patterns/registry.html
http://omurashov.ru/pattern-registry/
> чем Service Locator лучше
ServiceLocator это когда у нас есть класс, хранящий или умеющий создавать сервисы. и мы передаем его:
$classB = new ClassB($serviceLocator);
Собственно он плох тем что отравляет код, все объекты теперь должны принимать его в конструкторе. И вместо того чтобы указать явно какие сервисы нужны классу мы передаем ему сразу все. Это ухудшает код.
Но в контроллерах это удобно так как контроллер все равно нельзя повторно использовать, и ему нужно много сервисов, так что передавть их через конструктор неудобно. Для контроллера использовать SL (или передавать в него DI container что по сути то же самое) это вполне нормально. В симфони например так сделано.
Вот статья про него: http://sergeyteplyakov.blogspot.ru/2013/03/di-service-locator.html
Полный контроль дает только DI то есть передача serviceA в класс B через конструктор или сеттер.
>>514591
Да, но он не используется обычно.
>>514597
> Как я понял, единственное отличие, что Registry статический, а SL обычный класс,
Разница в том что SL передается в конструктор чтобы класс мог брать из него что ему надо. А Registry вообще чем-то напоминает глобальные переменные.
Погугли эти паттерны, почитай статьи.
DI это когда мы передаем классу A класс B снаружи и тем самым делаем эти классы менее спутанными. Обязательные зависимости обычно внедряются через конструктор, необязательные через сеттеры.
> Будет ли следующий пример реализацией этого паттерна:
Нет так как File это не сервис от которого зависит FileMapper. Это объект, с которым работает метод save.
А вот объект PDO в FileMapper стоит передавать именно через конструктор. Это позволяет внешнему коду решать какой именно объект какого класса будет использовать FileMapper для выполнения запросов.
>>514561
>Тут речь походу о синглтонах,
Не совсем то. Анон говорит про DI container то есть класс который содержит в себе экземпляры сервисов (должны же они где-то храниться).
>>514568
Registry это не очень хороший паттерн, так как он не обсепечивает DI. Он приведен в пример только чтобы показать что такой паттерн есть и может где-то используется.
Registry это когда в начале программы мы делаем:
Registry::set('serviceA', new ServiceA);
а в классе B делаем
$serviceA = Registry::get('serviceA');
Тут как видишь полноценной DI нет, мы не можем явно классу B передать экземпляр serviceA, он сам его берет из реестра.
Вот описание: http://design-pattern.ru/patterns/registry.html
http://omurashov.ru/pattern-registry/
> чем Service Locator лучше
ServiceLocator это когда у нас есть класс, хранящий или умеющий создавать сервисы. и мы передаем его:
$classB = new ClassB($serviceLocator);
Собственно он плох тем что отравляет код, все объекты теперь должны принимать его в конструкторе. И вместо того чтобы указать явно какие сервисы нужны классу мы передаем ему сразу все. Это ухудшает код.
Но в контроллерах это удобно так как контроллер все равно нельзя повторно использовать, и ему нужно много сервисов, так что передавть их через конструктор неудобно. Для контроллера использовать SL (или передавать в него DI container что по сути то же самое) это вполне нормально. В симфони например так сделано.
Вот статья про него: http://sergeyteplyakov.blogspot.ru/2013/03/di-service-locator.html
Полный контроль дает только DI то есть передача serviceA в класс B через конструктор или сеттер.
>>514591
Да, но он не используется обычно.
>>514597
> Как я понял, единственное отличие, что Registry статический, а SL обычный класс,
Разница в том что SL передается в конструктор чтобы класс мог брать из него что ему надо. А Registry вообще чем-то напоминает глобальные переменные.
Погугли эти паттерны, почитай статьи.
> И расскажите о "миграциях", потому что я слышал что не нужно лезть в базу и править таблицы руками, это нужно делать через эти самые миграции. Что это вообще?
Миграция это файл с кодом (SQL или PHP) который обновляет структуру базы данных. Очевидно он нужен чтобы сохранять изменения структуры в репозиторий (и иметь возможность получить структуру базы для любой ревизии) а также передавать сделанные тобой изменеия другим участникам команды и применять их на серверах.
Ну и это логично, база это часть приложения и информация о ней должна быть в репозитории.
А как иначе?
Обычно в фреймворках (Yii например) есть готовые шаблоны для миграций, тебе надо туда только SQL или команды создания таблиц дописать.
>>514615
Там нельзя ничего фиксить. надо писать свои темы и расширения. Иди читай мануал прежде чем брать задачи по вордпрессу.
Сделай команду apachectl -t -D DUMP_VHOSTS (или apache2ctl?). Она выводит список описанных в конфиге хостов и ты можешь проверить есть там твой хост или нет.
Не забудь перезапустить Апач также.
>>514633
Ты ерунду советуешь. Под линуксом обычно на каждый хост создают отдельный файл и их можно включать/отключать.
>>514657
Нет нельзя. Ты вообще не должен пытаться что-то делать с константой кроме присваивания или сравнения.
Также, ты не должен обращаться по индексу к обычным строкам так как это вернет не N-ю букву а N-й байт.
> Вроде бы в константе тоже строка, с чем это связано?
Ты неправильно пытаешься использовать константу.
> Мне эту переменную видимо придется жоско зашить в статичный метод, внутри которого она используется. А если эта строка мне понадобится в других методах?
Mb_substr используй, но мне кажется ты должен сделать тут не константу а статическое приватное свойство.
> Хм, я тогда сделаю статичный метод, который тупо возвращает эту строку.
Тоже хороший вариант.
>>514661
Странно, у меня на дебиане без судо просто не хватает прав:
$ service apache2 reload
Failed to reload apache2.service: Access denied
Дебиан 8, если что. Видимо убунтоводы где-то накосячили и это временный баг.
>>514664
По идее должен то, что надо перезагрузать. А вот изменения в php.ini он не применит наверно так как это не конфиг Апача и он про него не знает.
Сделай команду apachectl -t -D DUMP_VHOSTS (или apache2ctl?). Она выводит список описанных в конфиге хостов и ты можешь проверить есть там твой хост или нет.
Не забудь перезапустить Апач также.
>>514633
Ты ерунду советуешь. Под линуксом обычно на каждый хост создают отдельный файл и их можно включать/отключать.
>>514657
Нет нельзя. Ты вообще не должен пытаться что-то делать с константой кроме присваивания или сравнения.
Также, ты не должен обращаться по индексу к обычным строкам так как это вернет не N-ю букву а N-й байт.
> Вроде бы в константе тоже строка, с чем это связано?
Ты неправильно пытаешься использовать константу.
> Мне эту переменную видимо придется жоско зашить в статичный метод, внутри которого она используется. А если эта строка мне понадобится в других методах?
Mb_substr используй, но мне кажется ты должен сделать тут не константу а статическое приватное свойство.
> Хм, я тогда сделаю статичный метод, который тупо возвращает эту строку.
Тоже хороший вариант.
>>514661
Странно, у меня на дебиане без судо просто не хватает прав:
$ service apache2 reload
Failed to reload apache2.service: Access denied
Дебиан 8, если что. Видимо убунтоводы где-то накосячили и это временный баг.
>>514664
По идее должен то, что надо перезагрузать. А вот изменения в php.ini он не применит наверно так как это не конфиг Апача и он про него не знает.
Спасибо, про паттерны эти понятно стало.
На Phalcon
Прошу проверить данный код.
Интересно, как можно его улучшить, имея в запасе только те знания, что могли быть получены при работе с этим замечательный курсом: http://archive-ipq-co.narod.ru/.
http://ideone.com/ywckv8
Опять смуту вносишь, ебучий шакал?
>надо писать свои темы и расширения.
Я и писал свои темы и расширения, дебила кусок. Я даже не уверен, что это был ВП - цмска какая-то хитровыебанная, но организована как вп.
Но для этого нужно как минимум познать азы и набить руку, чем я упорно стараюсь заниматься.
https://github.com/V3N0m21/Uppu3
Поправил несколько моментов, чуть не сломал мозг делая custom type в доктрине, но все-равно до конца не уверен что все правильно, как-то слишком мудрено получилось, ну и в моем случае не дает никаких плюсов, разве что в целях обучения и понимания.
>При ресайзе маленькие картинки не увеличиваются? ЧТо-то я не вижу проверки на это.
Там стоит проверка на размер, и если одна из сторон меньше заданного размера, задается размер самой картинки
https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L55
>Стоит сделать проверку на наличие apc и при отсуствии откатываться на файловый кеш
https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L9
Поправил, но не уверен что это правильное решение, я так и не нашел четкого мануала по этому поводу, походу все приходят к пониманию этого методом проб и ошибок.
> {{ app.request.getRootUri() }}../css/bootstrap.min.css
>Что-то это странно. Зачем тут две точки? Мне кажется сразу должен идти путь. Что у тебя выдает getRootUri() ?
Это то о чем я говорил, что $app->getRootUri() возвращает не то что мне нужно, он показывает путь до файла index.php, то есть в моем случае он возвращает "/"
Остальные замечания подправлю и сделаю древовидные комменты, а сейчас интересует вопрос правильно ли я сделал custom type в доктрине
>>Стоит сделать проверку на наличие apc и при отсуствии откатываться на файловый кеш
> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L12
> $config->setQueryCacheImpl(new \Doctrine\Commmon\Cache\MemcacheCache());
По моему это не файловый кеш
> Это то о чем я говорил, что $app->getRootUri() возвращает не то что мне нужно, он показывает путь до файла index.php, то есть в моем случае он возвращает "/"
Ну и отлично, припиши к этому 'css/bootsrap.css' и получишь нужный путь который независим от текущего URL. Разве это то что надо?
> https://github.com/V3N0m21/Uppu3/blob/master/app/Resource/MediaInfo.php#L44
Эту функцию надо сделать либо нестатической либо сделать чтобы она сама создавала и возвращала объект. А то странно смотрится:
> $mediaInfo = $mediaInfo->setMediaInfo($mediaInfo, $info);
Ехал mediaInfo через mediaInfo.
Копипасту из ифов стоит заменить на список полей + цикл по нему.
json_decode лучше использовать с массивом, а не объектом StdClass, так как для работы с массивами есть много функций, а для StdClass нет.
Класс MediaInfoType лучше поместить в другую папку, например, Types.
> public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
Тут по идее должен возвращаться SQL-код для типа этого поля в MySQL (например если ты хочешь создать таблицу на основе аннотаций, доктрине надо знать какому типу поля соответствует твой тип). Посмоти как реализованы другие типы в доктрине и сделай по аналогии:
https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Types
Класс File стоит переименовать в FileUtil или FileUploader и перенести в другую папку.
Почему тип регистрируешь через
> Type::addType('mediainfotype', 'Uppu3\Resource\MediaInfoType');
А не как в мануале советуют,
> $conn->getDatabasePlatform()->registerDoctrineTypeMapping('db_mytype', 'mytype');
?
>>Стоит сделать проверку на наличие apc и при отсуствии откатываться на файловый кеш
> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L12
> $config->setQueryCacheImpl(new \Doctrine\Commmon\Cache\MemcacheCache());
По моему это не файловый кеш
> Это то о чем я говорил, что $app->getRootUri() возвращает не то что мне нужно, он показывает путь до файла index.php, то есть в моем случае он возвращает "/"
Ну и отлично, припиши к этому 'css/bootsrap.css' и получишь нужный путь который независим от текущего URL. Разве это то что надо?
> https://github.com/V3N0m21/Uppu3/blob/master/app/Resource/MediaInfo.php#L44
Эту функцию надо сделать либо нестатической либо сделать чтобы она сама создавала и возвращала объект. А то странно смотрится:
> $mediaInfo = $mediaInfo->setMediaInfo($mediaInfo, $info);
Ехал mediaInfo через mediaInfo.
Копипасту из ифов стоит заменить на список полей + цикл по нему.
json_decode лучше использовать с массивом, а не объектом StdClass, так как для работы с массивами есть много функций, а для StdClass нет.
Класс MediaInfoType лучше поместить в другую папку, например, Types.
> public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
Тут по идее должен возвращаться SQL-код для типа этого поля в MySQL (например если ты хочешь создать таблицу на основе аннотаций, доктрине надо знать какому типу поля соответствует твой тип). Посмоти как реализованы другие типы в доктрине и сделай по аналогии:
https://github.com/doctrine/dbal/tree/master/lib/Doctrine/DBAL/Types
Класс File стоит переименовать в FileUtil или FileUploader и перенести в другую папку.
Почему тип регистрируешь через
> Type::addType('mediainfotype', 'Uppu3\Resource\MediaInfoType');
А не как в мануале советуют,
> $conn->getDatabasePlatform()->registerDoctrineTypeMapping('db_mytype', 'mytype');
?
> как-то слишком мудрено получилось,
А что мудреного? Всего 15 строчек. Просто мы создали свой тип преобразования (маппинга) между значением в БД и значением поля объекта.
> ну и в моем случае не дает никаких плюсов,
Ты получаешь автоматическое сохранение объекта MediaInfo в базу и восстановлние из нее. Это по моему удобнее чем руками там прикручивать преобразование в json и обратно. То, что у тебя было раньше, не работало вообще так как json_decode не восстанавливает объект класса MediaInfo.
Даже ссылку на тред правильно не поменяли, ну их. И у нас всего 600 постов пока.
>>514851
> for ($i=0; $i<=strlen($lowercasedtext);$i++) {if (mb_substr($lowercasedtext,$i,1) != $empty) {
Чтобы убрать пробелы, используй функцию str_replace или strtr, заменяя пробелы на пустую строку.
>for ($ii=0; $ii <= $half; $ii++){
После $i можно использовать $j, $k, Они лучше читаются.
> strlen($without)-$ii-1
Тут ошибка. strlen возвращает длину в байтах, а не число букв (для русских букв не совпадает). Надо использоват mb_strlen. Почитай урок: https://gist.github.com/codedokode/ff99e357e9860ea169b8
> \tif ($ii == $half){
> echo "this word is a fucking PALINDROME, congrats, m8";
Это неправильно так как ты не можешь по совпадению только первой и последней букв сказать что слово палиндром. Надо проверить все.
И смотри внизу ошибку:
> PHP Notice: Undefined variable: without in /home/hz6bPR/prog.php on line 12
Ты обращаешься к несуществующей на тот момент переменной, надо сначала ей присвоить какое-нибудь значение а потом использовать.
Попробуй сделть чтобы программа работала с руссикми буквами. Если что, задавай вопросы.
>>514860
Тролль, уходи.
Даже ссылку на тред правильно не поменяли, ну их. И у нас всего 600 постов пока.
>>514851
> for ($i=0; $i<=strlen($lowercasedtext);$i++) {if (mb_substr($lowercasedtext,$i,1) != $empty) {
Чтобы убрать пробелы, используй функцию str_replace или strtr, заменяя пробелы на пустую строку.
>for ($ii=0; $ii <= $half; $ii++){
После $i можно использовать $j, $k, Они лучше читаются.
> strlen($without)-$ii-1
Тут ошибка. strlen возвращает длину в байтах, а не число букв (для русских букв не совпадает). Надо использоват mb_strlen. Почитай урок: https://gist.github.com/codedokode/ff99e357e9860ea169b8
> \tif ($ii == $half){
> echo "this word is a fucking PALINDROME, congrats, m8";
Это неправильно так как ты не можешь по совпадению только первой и последней букв сказать что слово палиндром. Надо проверить все.
И смотри внизу ошибку:
> PHP Notice: Undefined variable: without in /home/hz6bPR/prog.php on line 12
Ты обращаешься к несуществующей на тот момент переменной, надо сначала ей присвоить какое-нибудь значение а потом использовать.
Попробуй сделть чтобы программа работала с руссикми буквами. Если что, задавай вопросы.
>>514860
Тролль, уходи.
Блин, мне тоже хочется похвастаться файлообменником, давно не вбрасывал.
Но я там так криво прикрутил регистрацию, что лучше сначала сам поправлю те ошибки что вижу, потом покажу.
Как всегда оказалась тупая ошибка: перепутал местами, в одном месте написал sha1($salt . $password), а в другом sha1($password . $salt).
Надо учиться быть внимательным и анализировать, не сидеть и смотреть на него "чо ты не работаешь?", а разбивать код на кусочки и отслеживать построчно. Это хоть и рутинно при большом объеме кода, но дает плоды.
> .
> \tif ($ii == $half){
> echo "this word is a fucking PALINDROME, congrats, m8";
>Это неправильно так как ты не можешь по совпадению только первой и последней букв сказать что слово палиндром. Надо проверить все.
Я пытался сделать цикл в цикле, который сравнивает шаг прохождения с половиной длины слова, по достижению значения которого цикл завершался. Проверка велась как первая буква == последняя, вторая == предпоследняя, итд. Проверял выводом результата. (http://ideone.com/DNgLQV)
Вроде исправил.
Вот итог. http://ideone.com/YIgY9M
Спасибо!
Когда пользователь логинится, это что?
Аутентификация - это проверка соответствия субъекта и того, за кого он пытается себя выдать, с помощью некой уникальной информации (отпечатки пальцев, цвет радужки, голос и тд.), в простейшем случае - с помощью имени входа и пароля.
Авторизация - это проверка и определение полномочий на выполнение некоторых действий (например, чтение файла /var/mail/eltsin) в соответствии с ранее выполненной аутентификацией,
Подскажите фреймворк/cmf. Пока остановился на связке slim+twig+medoo.
Блин, только что закоммитил с комментарием "Добавил авторизацию", подразумевая вход через форму логин/пароль.
Как теперь исправить комментарий к коммиту?
Так, тут вроде либо --ammend -m, либо -c. Блин, такое полотно, хрен что найдешь.
Переведите
--amend
Replace the tip of the current branch by creating a new commit. The recorded tree is prepared
as usual (including the effect of the -i and -o options and explicit pathspec), and the
message from the original commit is used as the starting point, instead of an empty message,
when no other message is specified from the command line via options such as -m, -F, -c, etc.
The new commit has the same parents and author as the current one (the --reset-author option
can countermand this).
-c <commit>, --reedit-message=<commit>
Like -C, but with -c the editor is invoked, so that the user can further edit the commit
message.
Оно мне только исправит комментарий к коммиту, или создаст новый?
Ты там какую-то йобу строишь с блэкджеком и шлюхами, а у меня простой файлообменник как написано в минимальной инструкции к задаче. А вообще я завидую твоему энтузиазму, мне очень сложно начать делать что-то просто из интереса, нужно какое-то сверхусилие над собой, но после того как начал оно идет само собой. Мне вот например для этого нужны комменты ОПа, сам я почему-то не могу заставить себя прикручивать что-то сверх нормы, внутри включается режим "и так пойдет", и хз как это искоренять
но там нужно в качестве ответа использовать json, который я не шарю, читал вот здесь https://learn.javascript.ru/json
и вроде понятно как таковой объект создать, но как его вернуть, в php я бы вернул с помощью echo, а как вернуть это?
Почитай https://www.devbridge.com/sourcery/components/jquery-autocomplete/
хочу вернуть результат выборки.
Ну не пилить же под каждый виджет типа плеера или древовидных комментариев отдельный проект. Поэтому я все туда сую.
Плюс я собираюсь это дело показывать в качестве примера выполненных работ (в моей мухосрани 50% работодателей просят что-то показать, а что я им покажу? задачку на айфон в кредит?)
Хотя пожалуй задание действительно на это не рассчитано, бедный слим уже раздуло от большого количества кода.
По поводу мотивации не могу ничего советовать. Мною движет желание обеспечить себе комфортную обстановку в плане психологии и финансов. Я знаю что мне нужно, и я иду к этому.
ну на сервер идет запрос, я клиенту возвращаю ответ. всё как обычно.
А эта хуйня Ajax AutoComplete for jQuery требует, чтобы я ей(клиенту) возвращал данные в json объекте.
>Response Format
Response from the server must be JSON formatted following JavaScript object:
{
// Query is not required as of version 1.2.5
"query": "Unit",
"suggestions": [
{ "value": "United Arab Emirates", "data": "AE" },
{ "value": "United Kingdom", "data": "UK" },
{ "value": "United States", "data": "US" }
]
}
Data can be any value or object. Data object is passed to formatResults function and onSelect callback. Alternatively, if there is no data you can supply just a string array for suggestions:
{
"query": "Unit",
"suggestions": ["United Arab Emirates", "United Kingdom", "United States"]
}
>>515056
Так возвращай данные в json, в чем проблема? JSON - это просто форматированная определенным образом строка, ничгео сложного ведь.
http://www.objgen.com/json?demo=true - json генератор
http://jsonlint.com/ - чекер json
http://php.net/manual/ru/function.json-encode.php
http://php.net/manual/ru/function.json-decode.php
допустим в файле, в котором обрабатываю запрос у меня есть
$response = '{
"query": "Unit",
"suggestions": [
{ "value": "United Arab Emirates", "data": "AE" },
{ "value": "United Kingdom", "data": "UK" },
{ "value": "United States", "data": "US" }
]
}';
echo json_encode($response);
но тогда ответ пикрелейтед, что за хуйня? зачем экранирует?!
если это вбить в http://jsonlint.com/
то оно мне пишет:
Parse error on line 1:
"{ \r\n\r\n\"que
^
Expecting '{', '['
что я делаю не так?
Учтены все замечания, озвученные здесь: >>511406
Осталось прикрутить пагинацию к html-шаблону. Честно говоря, я пока не особо представляю, как это сделать по-человечески.
Я имею в виду сделать по-умному. Чтоб номер текущей страницы красился в другой цвет (с этим понятно), чтоб слева и справа от текущей страницы показывалось только заданное число номеров других страниц (а дальше -- многоточие) и тому подобные вещи. Идеально, если эти параметры можно без труда настроить PHP-кодом.
> тупая ошибка: перепутал местами, в одном месте написал sha1($salt . $password), а в другом sha1($password . $salt).
Твоя ошибка в том что ты код который делает одно и то же пишешь 2 раза, а не выносишь в функцию. Дублирования кода быть не должно.
Ты не уделил должного внимания изуению формата JSON и чтению мануалп по JSON_encode. Не разобрал все примеры кода в мануале по этой функции.
> $response = '{
> echo json_encode($response);
Ты посмотри что он тебе выводит. Ты должен видеть
{ ...
а видишь
"{ ...
Тебя это не удивляет? Кавычка это не такая вещь которую можно проигнорировать так как она полностью меняет весь смысл. Начни с чтения википедии:
https://ru.wikipedia.org/wiki/JSON
Ты подаешь на вход json_encode строку и получаешь на выходе закодированную в JSON эту строку. А виджету нужна не строка, а словарь (хеш) описанного формата.
На вход json_encode надо подавать правильно сформированный массив с данными (так как в php нет словарей то и JSON-массив и JSON-словарь на строне PHP обозначается массивом). перечитай мануал PHP и внимательно посмотри примеры кода в нем.
> то оно мне пишет:
> Parse error on line 1:
> "{ \r\n\r\n\"que
> ^
> Expecting '{', '['
Все правильно пишет. JSON объект на самом верхнем уровне по стандарту должен быть словарем либо массивом, а не строкой.
Также, JSON ответ должен иметь заголовок Content-Type: application/json
Не забудь поставить соответствующий header().
Ты не уделил должного внимания изуению формата JSON и чтению мануалп по JSON_encode. Не разобрал все примеры кода в мануале по этой функции.
> $response = '{
> echo json_encode($response);
Ты посмотри что он тебе выводит. Ты должен видеть
{ ...
а видишь
"{ ...
Тебя это не удивляет? Кавычка это не такая вещь которую можно проигнорировать так как она полностью меняет весь смысл. Начни с чтения википедии:
https://ru.wikipedia.org/wiki/JSON
Ты подаешь на вход json_encode строку и получаешь на выходе закодированную в JSON эту строку. А виджету нужна не строка, а словарь (хеш) описанного формата.
На вход json_encode надо подавать правильно сформированный массив с данными (так как в php нет словарей то и JSON-массив и JSON-словарь на строне PHP обозначается массивом). перечитай мануал PHP и внимательно посмотри примеры кода в нем.
> то оно мне пишет:
> Parse error on line 1:
> "{ \r\n\r\n\"que
> ^
> Expecting '{', '['
Все правильно пишет. JSON объект на самом верхнем уровне по стандарту должен быть словарем либо массивом, а не строкой.
Также, JSON ответ должен иметь заголовок Content-Type: application/json
Не забудь поставить соответствующий header().
Ты ошибаешься, смотри мой пост.
>>515216
и когда новую версию XHTML увидим? Учитывая что старую практически никто никогда не использовал за все время ее существования (все использовали HTML 4, а позже HTML 5), то новую вряд ли ждет успех.
>>515222
Сделай объект генерирубющий массив из цифр и ссылок. А шаблон проходит по этому массиву и оформляет его в виде HTML тегов.
Там по моему в комментариях к заадче написано же.
https://github.com/codedokode/pasta/blob/master/student-list.md#Постраничная-навигация
Для вывода двоеточия в объекте можно сделать методы говоряшие надо его выводить или не надо в данном случае.
>>515224
Бразеры пока отображают HTML а не jSOn. Да и в hTML как минимум тегов больше.
>>515230
Если ты не разбираешься в проблеме не давай бессмысленных и запутывающих советов. Какие преимущества тут дает использование JS? С пагинауией после ее вывода ничего не происходит. Никаких очевидно, значит он не нужен.
Ты тролль или просто дебил?
Ты ошибаешься, смотри мой пост.
>>515216
и когда новую версию XHTML увидим? Учитывая что старую практически никто никогда не использовал за все время ее существования (все использовали HTML 4, а позже HTML 5), то новую вряд ли ждет успех.
>>515222
Сделай объект генерирубющий массив из цифр и ссылок. А шаблон проходит по этому массиву и оформляет его в виде HTML тегов.
Там по моему в комментариях к заадче написано же.
https://github.com/codedokode/pasta/blob/master/student-list.md#Постраничная-навигация
Для вывода двоеточия в объекте можно сделать методы говоряшие надо его выводить или не надо в данном случае.
>>515224
Бразеры пока отображают HTML а не jSOn. Да и в hTML как минимум тегов больше.
>>515230
Если ты не разбираешься в проблеме не давай бессмысленных и запутывающих советов. Какие преимущества тут дает использование JS? С пагинауией после ее вывода ничего не происходит. Никаких очевидно, значит он не нужен.
Ты тролль или просто дебил?
>https://github.com/codedokode/pasta/blob/master/student-list.md#Постраничная-навигация
Что-то я упустил это. Попробую завтра разобраться.
https://ideone.com/qM0fUW
Накоплено 10000 и петушку уже 16 лет
Накоплено 11000 и петушку уже 17 лет
Накоплено 12100 и петушку уже 18 лет
Накоплено 13310 и петушку уже 19 лет
Накоплено 14641 и петушку уже 20 лет
Накоплено 16105.1 и петушку уже 21 лет
Накоплено 17715.61 и петушку уже 22 лет
Накоплено 19487.171 и петушку уже 23 лет
Накоплено 21435.8881 и петушку уже 24 лет
Накоплено 23579.47691 и петушку уже 25 лет
Накоплено 25937.424601 и петушку уже 26 лет
Накоплено 28531.1670611 и петушку уже 27 лет
Накоплено 31384.28376721 и петушку уже 28 лет
Накоплено 34522.712143931 и петушку уже 29 лет
Накоплено 37974.983358324 и петушку уже 30 лет
Накоплено 41772.481694157 и петушку уже 31 лет
Накоплено 45949.729863572 и петушку уже 32 лет
Накоплено 50544.702849929 и петушку уже 33 лет
Накоплено 55599.173134922 и петушку уже 34 лет
Накоплено 61159.090448415 и петушку уже 35 лет
Накоплено 67274.999493256 и петушку уже 36 лет
Накоплено 74002.499442582 и петушку уже 37 лет
Накоплено 81402.74938684 и петушку уже 38 лет
Накоплено 89543.024325524 и петушку уже 39 лет
Накоплено 98497.326758076 и петушку уже 40 лет
Накоплено 108347.05943388 и петушку уже 41 лет
Накоплено 119181.76537727 и петушку уже 42 лет
Накоплено 131099.941915 и петушку уже 43 лет
Накоплено 144209.9361065 и петушку уже 44 лет
Накоплено 158630.92971715 и петушку уже 45 лет
Накоплено 174494.02268886 и петушку уже 46 лет
Накоплено 191943.42495775 и петушку уже 47 лет
Накоплено 211137.76745353 и петушку уже 48 лет
Накоплено 232251.54419888 и петушку уже 49 лет
Накоплено 255476.69861877 и петушку уже 50 лет
Накоплено 281024.36848064 и петушку уже 51 лет
Накоплено 309126.80532871 и петушку уже 52 лет
Накоплено 340039.48586158 и петушку уже 53 лет
Накоплено 374043.43444774 и петушку уже 54 лет
Накоплено 411447.77789251 и петушку уже 55 лет
Накоплено 452592.55568176 и петушку уже 56 лет
Накоплено 497851.81124994 и петушку уже 57 лет
Накоплено 547636.99237493 и петушку уже 58 лет
Накоплено 602400.69161242 и петушку уже 59 лет
Накоплено 662640.76077367 и петушку уже 60 лет
Накоплено 728904.83685103 и петушку уже 61 лет
Накоплено 801795.32053614 и петушку уже 62 лет
Накоплено 881974.85258975 и петушку уже 63 лет
Накоплено 970172.33784873 и петушку уже 64 лет
https://ideone.com/qM0fUW
Накоплено 10000 и петушку уже 16 лет
Накоплено 11000 и петушку уже 17 лет
Накоплено 12100 и петушку уже 18 лет
Накоплено 13310 и петушку уже 19 лет
Накоплено 14641 и петушку уже 20 лет
Накоплено 16105.1 и петушку уже 21 лет
Накоплено 17715.61 и петушку уже 22 лет
Накоплено 19487.171 и петушку уже 23 лет
Накоплено 21435.8881 и петушку уже 24 лет
Накоплено 23579.47691 и петушку уже 25 лет
Накоплено 25937.424601 и петушку уже 26 лет
Накоплено 28531.1670611 и петушку уже 27 лет
Накоплено 31384.28376721 и петушку уже 28 лет
Накоплено 34522.712143931 и петушку уже 29 лет
Накоплено 37974.983358324 и петушку уже 30 лет
Накоплено 41772.481694157 и петушку уже 31 лет
Накоплено 45949.729863572 и петушку уже 32 лет
Накоплено 50544.702849929 и петушку уже 33 лет
Накоплено 55599.173134922 и петушку уже 34 лет
Накоплено 61159.090448415 и петушку уже 35 лет
Накоплено 67274.999493256 и петушку уже 36 лет
Накоплено 74002.499442582 и петушку уже 37 лет
Накоплено 81402.74938684 и петушку уже 38 лет
Накоплено 89543.024325524 и петушку уже 39 лет
Накоплено 98497.326758076 и петушку уже 40 лет
Накоплено 108347.05943388 и петушку уже 41 лет
Накоплено 119181.76537727 и петушку уже 42 лет
Накоплено 131099.941915 и петушку уже 43 лет
Накоплено 144209.9361065 и петушку уже 44 лет
Накоплено 158630.92971715 и петушку уже 45 лет
Накоплено 174494.02268886 и петушку уже 46 лет
Накоплено 191943.42495775 и петушку уже 47 лет
Накоплено 211137.76745353 и петушку уже 48 лет
Накоплено 232251.54419888 и петушку уже 49 лет
Накоплено 255476.69861877 и петушку уже 50 лет
Накоплено 281024.36848064 и петушку уже 51 лет
Накоплено 309126.80532871 и петушку уже 52 лет
Накоплено 340039.48586158 и петушку уже 53 лет
Накоплено 374043.43444774 и петушку уже 54 лет
Накоплено 411447.77789251 и петушку уже 55 лет
Накоплено 452592.55568176 и петушку уже 56 лет
Накоплено 497851.81124994 и петушку уже 57 лет
Накоплено 547636.99237493 и петушку уже 58 лет
Накоплено 602400.69161242 и петушку уже 59 лет
Накоплено 662640.76077367 и петушку уже 60 лет
Накоплено 728904.83685103 и петушку уже 61 лет
Накоплено 801795.32053614 и петушку уже 62 лет
Накоплено 881974.85258975 и петушку уже 63 лет
Накоплено 970172.33784873 и петушку уже 64 лет
Наркоман?
> конечный возраст ставить твердое число? (петушку будет 65), или высчитывать дробное? икак вообще правильне доделать?
Целое, возраст обычно никто не пишет в дробном виде, да и банк начисляет проценты не каждый день, а раз в месяц или год.
> while ($deposit <= 1000000){
> \tfor ($deposit = 10000; $deposit <= 1000000; $deposit = $deposit * $bankRate) {
Тут один из циклов лишний. Используй либо while либо for но не все сразу.
переменную area, я же ее объявил не в функции, а выше.
хелп ми плиз
var area = null;
var areas = [
<?php echo substr("$areas", 0, -1)?>
];
$('#area').autocomplete({
lookup: areas,
onSelect: function (suggestion) {
area = suggestion.data;
alert(area);
}
});
$('#city').autocomplete({
serviceUrl: 'autocomplete.php',
params: {
'area': area
},
onSelect: function (suggestion) {
alert('You selected: ' + suggestion.value + ', ' + suggestion.data);
}
});
ОП, подскажи по поводу древовидных комментов:
С Doctrine Extensions я разобраться не могу вообще. Все стопорится еще на этапе инициализации в bootstrap.php, коротко - я не могу понять как прикрутить AnnotationReader. Пример который у них там предложен мне не помогает, а скорее наоборот еще сильнее запутывает, если можешь направить меня, было бы отлично, потому что я перерыл все что мог перерыть и ничего не нашел, мне бы подошел чей-то рабочий код или еще что-нибудь в этом роде.
Походу мне кажется чтоб разобраться придется перечитывать всю документацию по Доктрине чтоб понять что, куда, откуда вызывает и берется.
Пока решил делать комменты просто средствами доктрины как adjacency list, и появился вопрос, чтоб передать parentId в форму, мне нужно обязательно прикручивать jQuery, или этому есть альтернатива?
а где у нас дают дипломы веб-прогромиста, педик?
В миллионниках без проблем. У хирурга человек сдохнет, а у программера всего лишь сайт заглючит, в крайнем случае другого посадят допиливать, убытков никаких. Поэтому берут всех подряд, даже бомжей.
иди нахуй отсюда, дебил.
Ну теперь, в принципе, всё готово: https://github.com/blackberryJam/abiturients
Кроме 404-й страницы.
С пагинацией разобрался, можно настраивать диапазон отображаемых номеров страниц.
Ему нужно подсовывать в конфигурацию данные, которые я теоретически могу взять прямо из страницы, потому что у меня выше плеера идет таблица с описанием файла. Но меня смущает, что дизайнер/верстальщик в любой момент может изменить страницу, выкинуть из нее некоторые элементы, и у меня сдохнет плеер. Значит все-таки лучше сделать явный xhr-запрос к серверу?
А вообще с фреймворками работал?
Вообще вряд ли ты быстро в нем разберешься, но почитай оф. документацию, там примеры есть841
Мне уже напомнили о существовании капчи в этом случае. Кстати какие можно написать полезные скрипты используя АПИ вконтакте, кроме авторизации и комментариев? Вроде бы и функций столько есть, только не понимаю что можно нормальное написать при помощи всего этого.
С wordpress и typo3 работал. Ну попробую, просто оф. документация длинная и запутанная, думал может чего для нубов есть, в стиле w3schools или сайта ОПа.
Синхронные аякс запросы использовать недопустимо так как они блокируют браузер и интерфейс пользователя. Это фича из прошлого, которая в светлом будущем не нужна.
Ну и? Что предлагаешь?
Ставить какую-нибудь костыльную задержку? Есть в js аналог sleep? setTimeout?
бесконечный цикл, который чекает переменную. Из эвента аякса кладется в переменную.
> Ему нужно подсовывать в конфигурацию данные, которые я теоретически могу взять прямо из страницы,
Это неправильно. А если данные как-то модифицируются для представления пользователю, форматируются и тд, ты будешь делать преобразования в обратном порядке? Это непрваильно.
Если тебе нужно заложить какие-то данные в DOm-элемент, можно использовать data-атрибуты, например:
<img src="small.jpg" data-full-size="big.jpg" alt="">
Но тут все еще проще. Тебе можно передать данные напрямую в JS-скрипт:
<script>
var path = 'audio.mp3';
initPlayer(path);
</script>
Как корректно подставить данные из PHP в JS-строку, соблюдая все правила экранирования спецсимволов? Раньше я писал для этого свою функцию, но потом обнаружил что существует готовая:
var path = <?= json_encode($phpString) ?>;
Так как JSON это подмножество JS то любое JSON-закодированное значение является корректным значением в яваскрипте и мы можем смело присвоить его переменной, и не бояться что полуим ошибку JS. Таким образом можно передавать значения null, false|true, цифры, строки, массивы и словари.
Заметь что кавычки ставить не надо.
Заметь что мы не используем здесь htmlspecialchars. Почему? Потому, что теги script и style имеют особый тип содержимого: в них не интерпретируются html-сущности вроде </ и в них угловые скобки не обозначают теги, а передаются js- или css-движку как есть. Потому при вставке данных внутрь style/script не надо их экранировать. Единственное, в этих данных не должна встречаться последовательность
</
которая браузером может интерпретироватся как конец тега script/style. json_encode заменяет / на \/ потому в ее результате такая последовательность встретиться не может.
Это относится только к тегам script/style. Если ты хочешь вставить js-переменную, например в атрибут тега, ты обязан ее экранировать по всем правилам (json_encode преобразует ее в JS-значение, htmlspecialchars экранирует спецсимволы в значении атрибута):
<div onclick="doSmth(<?= htmlspecialchars(json_encode($value), ENT_QUOTES) ?>)">
Собственно, это был мини-урок на тему «как передать переменную в JS».
Аякс-запросы тут не лучшая идея так как мы без необходимости усложняем код. зачем делать сложно если можно сделать просто?
> Ему нужно подсовывать в конфигурацию данные, которые я теоретически могу взять прямо из страницы,
Это неправильно. А если данные как-то модифицируются для представления пользователю, форматируются и тд, ты будешь делать преобразования в обратном порядке? Это непрваильно.
Если тебе нужно заложить какие-то данные в DOm-элемент, можно использовать data-атрибуты, например:
<img src="small.jpg" data-full-size="big.jpg" alt="">
Но тут все еще проще. Тебе можно передать данные напрямую в JS-скрипт:
<script>
var path = 'audio.mp3';
initPlayer(path);
</script>
Как корректно подставить данные из PHP в JS-строку, соблюдая все правила экранирования спецсимволов? Раньше я писал для этого свою функцию, но потом обнаружил что существует готовая:
var path = <?= json_encode($phpString) ?>;
Так как JSON это подмножество JS то любое JSON-закодированное значение является корректным значением в яваскрипте и мы можем смело присвоить его переменной, и не бояться что полуим ошибку JS. Таким образом можно передавать значения null, false|true, цифры, строки, массивы и словари.
Заметь что кавычки ставить не надо.
Заметь что мы не используем здесь htmlspecialchars. Почему? Потому, что теги script и style имеют особый тип содержимого: в них не интерпретируются html-сущности вроде </ и в них угловые скобки не обозначают теги, а передаются js- или css-движку как есть. Потому при вставке данных внутрь style/script не надо их экранировать. Единственное, в этих данных не должна встречаться последовательность
</
которая браузером может интерпретироватся как конец тега script/style. json_encode заменяет / на \/ потому в ее результате такая последовательность встретиться не может.
Это относится только к тегам script/style. Если ты хочешь вставить js-переменную, например в атрибут тега, ты обязан ее экранировать по всем правилам (json_encode преобразует ее в JS-значение, htmlspecialchars экранирует спецсимволы в значении атрибута):
<div onclick="doSmth(<?= htmlspecialchars(json_encode($value), ENT_QUOTES) ?>)">
Собственно, это был мини-урок на тему «как передать переменную в JS».
Аякс-запросы тут не лучшая идея так как мы без необходимости усложняем код. зачем делать сложно если можно сделать просто?
Вообще в таких случаях надо ипользовать асинхроннуое программирование. Функция должна не возвращать значение, а вызывать колбкек:
function getVariable(onSuccess, onError) {
...
}
// использование:
getVariable(function (result) {
...
}, function (error) {
...
});
Если у тебя будет много асинхронных функций, то код будет напоминать кашу из вложенных друг в друга коллбеков. В таком случае ты можешь избавиться от них, используя Promise (обещания). В новых браузерах они будут встроены, для остальных надо подключить библиотеку.
C promise асинхронный код выглядит так:
var promise = getVariable(); // функция возвращет объект promise
// задаем обработчики для успеха/неудачи выполнения запроса
promise.then(function (result) {
...
}, function (error) {
....
});
Чтобы промиз работал, твоя функция getVariable должна выглядеть примерно так:
function getVariable() {
var promise = new Promise();
....
if (isOk) {
result = JSON.parse(...);
promise.resolve(result); // вызвает обраьотчик успешноо завершения
} else {
promise.reject('error text '); // вызвает обработчик ошибки
}
....
return promise;
}
Этот код выглядит похоже на предыдущий, тут тоже коллбеки, но если бы у нас была не одна асинхронная функция, а много, то с промизами код будет выглядеть чище. Промисы можно возвращать и передавать в функции как обычные переменные, и с ними мы пишем линейный код, а не кучу вложенных друг в друга коллбеков.
Мануал: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise
Вот старая статья про асинхронное программрование: http://javascript.ru/unsorted/async (там вместо промизов используют самописный аналог).
Кстати твой код делающий ajax запрос никак не обрабатывает ошибки. Это плохо, такой код нельзя делать, тем более в учебном задании. Всегда проверяй и обрабатывай возможные ошибки.
Вообще в таких случаях надо ипользовать асинхроннуое программирование. Функция должна не возвращать значение, а вызывать колбкек:
function getVariable(onSuccess, onError) {
...
}
// использование:
getVariable(function (result) {
...
}, function (error) {
...
});
Если у тебя будет много асинхронных функций, то код будет напоминать кашу из вложенных друг в друга коллбеков. В таком случае ты можешь избавиться от них, используя Promise (обещания). В новых браузерах они будут встроены, для остальных надо подключить библиотеку.
C promise асинхронный код выглядит так:
var promise = getVariable(); // функция возвращет объект promise
// задаем обработчики для успеха/неудачи выполнения запроса
promise.then(function (result) {
...
}, function (error) {
....
});
Чтобы промиз работал, твоя функция getVariable должна выглядеть примерно так:
function getVariable() {
var promise = new Promise();
....
if (isOk) {
result = JSON.parse(...);
promise.resolve(result); // вызвает обраьотчик успешноо завершения
} else {
promise.reject('error text '); // вызвает обработчик ошибки
}
....
return promise;
}
Этот код выглядит похоже на предыдущий, тут тоже коллбеки, но если бы у нас была не одна асинхронная функция, а много, то с промизами код будет выглядеть чище. Промисы можно возвращать и передавать в функции как обычные переменные, и с ними мы пишем линейный код, а не кучу вложенных друг в друга коллбеков.
Мануал: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Promise
Вот старая статья про асинхронное программрование: http://javascript.ru/unsorted/async (там вместо промизов используют самописный аналог).
Кстати твой код делающий ajax запрос никак не обрабатывает ошибки. Это плохо, такой код нельзя делать, тем более в учебном задании. Всегда проверяй и обрабатывай возможные ошибки.
Уже сделал аяксом. Ну ладно, завтра перепишу. Лучше перестараться, чем недостараться.
У меня там используется смарти. Он точно обрабатывает код внутри тега <script>?
Погоди, я тогда не смогу вынести js-код во внешний файл, раз ты мне предлагаешь подставлять что-то из php.
>>515857
Ладно, заврта перечитаю твои кантаты, я замаялся, спать хочу.
Попрактиковаться в асинхронном программировании и промизах ты можешь, реализовав аякс-отправку древовидных комментариев. Не забудь обрабатывать как ошибки связи с сервером так и ошибки валидации комментария.
Также, так как это учебное задание, сделай форму отправки так, чтобы она работала и без яваскрипта или при возникновении ошибки в JS коде (то есть чтобы в этом случае слался обычный POST-запрос с перезагрузкой страницы. Это лучше чем ничего).
> У меня там используется смарти. Он точно обрабатывает код внутри тега <script>?
Думаю, да. Смарти не пытается анализировать HTML код и ему без разницы какой там тег. Также, имей в виду смарти довольно древний и он не очень красивый с токи зрения синтаксиса, архитектуры, и тд. Я бы советовал еще изучить twig, он современный и лучше на мой взгляд. И он используется в симфони.
> Погоди, я тогда не смогу вынести js-код во внешний файл, раз ты мне предлагаешь подставлять что-то из php.
Код функции ты выносишь во внешний файл, а вызов вставляешь в страницу маленьким inline-скриптом.
Но потом мне сказали, что если душа не лежит к программированию, я только из-за денег, то я ничего не добьюсь.
Поэтому я принял решение уйти из треда.
Интересно конечно, XML, XSLT — помню, они считались многообещающими технологиями, а сейчас как-то отошли. Справедливости ради, тот же XSLT очень громоздкий, из него нельзя вызывать php-функции, и в сравнении с twig проигрывает подчистую.
Ок, теперь верно, но читаемость кода плохая.
Во-первых, слова в переменной надо разделять:
> $originaltext
$originalText
Во-вторых, не стоит городить такие длинные выражения и копипастить их по 2 раза:
> echo mb_substr($lowercasedtext, $j, 1) . " and " . mb_substr($lowercasedtext, mb_strlen($lowercasedtext) - $j-1, 1)."\n";
Помести это в переменные, например $letter1 и $letter2
Также, чтобы взять послеюнюю букву не надо считать длину, достаточно передать -1 в качестве номера:
$lastLetter = mb_substr($text, -1, 1);
Ну и часть комментариев по моему лишняя, например комментарий над функцией mb_strtolower не добавляет никакой новой информации.
> не понимаю, почему последняя функция не видит
переменную area,
Открой оладчик в браузере (Ctrl + shift + I), поставь точку остановва внутри функции и разберись что там видно.
Статья http://learn.javascript.ru/debugging-chrome
>>515466
> Все стопорится еще на этапе инициализации в bootstrap.php, коротко - я не могу понять как прикрутить AnnotationReader.
Согласен, в документации все очень запутанно. Давай посмотрим на пример отсюда:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup
и код отсюда: https://github.com/Atlantic18/DoctrineExtensions/blob/master/example/em.php
Здесь важно отличать общую инициализацию доктрины от того места, где подключается нужное расширение. Нам нужно только оно.
Во-первых, все проблемы с автозагрузкой должен решать композер. Ты не должен о ней беспокоиться, так что весь код относящийся к ней пропускаем.
Далее, там идет создание AnnotationReader — но это часть доктрины и у тебя он и так уже создается, может быть только неявно, при вызове
> Setup::createAnnotationMetadataConfiguration
(загляни в эту функцию и посмотри что она делает и что вызывает. Ты увидишь что она создает и AnnotationReader, и кеш пытается сама прикрутить)
Далее идет вызов
> Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM
Вот это уже инетереснее, так как возможно это нам нужно, чтобы расширения могли читать адресованные им аннотации, они встраивают свой драйвер в цепочку, которая занимается их чтением. Вот исходник этой функции: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/DoctrineExtensions.php#L35
Схема тут довольно сложная, но если разобраться, вот как выглядит построенная иерархия:
Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain
- AnnotationDriver // тот что создается в registerAbstractMappingIntoDriverChainORM
--CachedReader
---AnnotationReader
- AnnotationDriver // работает с папкой с твоими сущностями
-- CachedReader
--- AnnotationReader
Как видишь, тут мы вместо одного AnnotationDriver создаем цепочку из 2, один нацелен на папку DoctrineExtensions/../Entity, другой на твои сущности.
AnnotationDriver это штука которая читает и анализирует аннотации прописанные например в классе FileResource, кеш там стоит чтобы не делать это на каждый запрос, а только первый раз.
Я посмотрел папку DoctrineExtensions/lib/Tree/Entity, там всего один класс AbstractClosure, я думаю, если ты его не используешь (и если тебе нужно только расширение Tree) то эта цепочка тебе не требуется. Но в качестве упражнения, пожалуй, стоит ее реализовать. Можешь вынести это в отдельную функцию в bootstrap.php
Не забудь что там надо везде передать выбранный нами драйвер кеша, а не то что функции подсовывают по умолчанию.
Посмотри исходники упомянутых функций и разберись как создается эта цепочка.
От тебя требуется создать описанную выше иерархию.
Смотрим код примера дальше.
>// general ORM configuration
> $config = new Doctrine\ORM\Configuration;
Это как я уже написал выше, делается при вызове Setup::createAnnotationMetadataConfiguration и потому не нужно. От нас требуется лишь передать в нужное место созданный выше DriverChain с 2 драйверами аннотаций. Так как функция createAnnotationMetadataConfiguration не позволяет задать драйвер (она создает его сама), то мы от нее отказываемся и заменяем на Setup::createConfiguration после чего ставим в качестве драйвера аннотаций нашу DriverChain.
> $sluggableListener = new Gedmo\Sluggable\SluggableListener;
> $loggableListener = new Gedmo\Loggable\LoggableListener;
> $timestampableListener = new Gedmo\Timestampable\TimestampableListener;
Тут расширения добавляют свои обработчики событий (то есть они будут вызываться например после загрузки сущности из БД или перед сохранением). так как мы не используем эти расширения то можно их не добавлять.
> $treeListener = new Gedmo\Tree\TreeListener;
А вот это нужно, так как мы его используем.
Ну вот и все, то есть реально нужно сделать только 2 вещи:
— сделать цепочку из 2 annotation driver (реально не нужно, но в качестве управжнения стоит сделать)
— добавить обработчик событий от расширения Tree в доктрину
Ну а далее изучай как исопльзуется Tree. Во-первых, ты должен разметить свою сущность, пометив используемые для реализации дерева поля с помощью аннотаций:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md#tree-entity-example
Во-вторых, расширение добавляет в репозиторий дополнительные методы для работы с деревом:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md#using-repository-functions
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md#repository-methods-all-strategies
Насчет выбора стратегии:
> Пока решил делать комменты просто средствами доктрины как adjacency list,
Не пойдет. Такие комментарии нельзя эффективно выбирать. Почитай май урок, по моему materialized path для комментариев идеален, быстрая вставка и быстрая выборка в уже отсортированном виде.
> чтоб передать parentId в форму, мне нужно обязательно прикручивать jQuery, или этому есть альтернатива?
Есть такие альтернативы:
- чистый JS/DOm без jQuery
- если ты не силен в JS то можно для начала сделать просто радиокнопки перед каждым комментаием, выбирающий parentId. Радиокнопки средствами CSS можно превратить в кнопку «ответить» и заодно сделать подсветку выбранного комментария.
В перспективе надо бы сделать кнопку «ответить» которая через JS вставляет форму, заполняет в ней parentId, а затем аяксом отправляет. На случай пробелм с JS хорошо бы предусмотреть неаяксовую отправку если не сработал JS-код или если он отключен.
Не забудь при отправке аякс-запроса блокировать форму и обрабатывать сетевые ошибки с возможностью повторить попытку. Не забудь валидацию комментария на сервере и вывод списка ошибок. Если грамотно это спроектировать, то для обработки аякс- и не-аякс отправки можно использовать один и тот же код с парой ифов (для аякса например он отдает ответ в JSON, а при неаяксовой отправке делает редирект на страницу с комментариями).
Если какие-то вопросы или уточнения, спрашивай.
> не понимаю, почему последняя функция не видит
переменную area,
Открой оладчик в браузере (Ctrl + shift + I), поставь точку остановва внутри функции и разберись что там видно.
Статья http://learn.javascript.ru/debugging-chrome
>>515466
> Все стопорится еще на этапе инициализации в bootstrap.php, коротко - я не могу понять как прикрутить AnnotationReader.
Согласен, в документации все очень запутанно. Давай посмотрим на пример отсюда:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/annotations.md#em-setup
и код отсюда: https://github.com/Atlantic18/DoctrineExtensions/blob/master/example/em.php
Здесь важно отличать общую инициализацию доктрины от того места, где подключается нужное расширение. Нам нужно только оно.
Во-первых, все проблемы с автозагрузкой должен решать композер. Ты не должен о ней беспокоиться, так что весь код относящийся к ней пропускаем.
Далее, там идет создание AnnotationReader — но это часть доктрины и у тебя он и так уже создается, может быть только неявно, при вызове
> Setup::createAnnotationMetadataConfiguration
(загляни в эту функцию и посмотри что она делает и что вызывает. Ты увидишь что она создает и AnnotationReader, и кеш пытается сама прикрутить)
Далее идет вызов
> Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM
Вот это уже инетереснее, так как возможно это нам нужно, чтобы расширения могли читать адресованные им аннотации, они встраивают свой драйвер в цепочку, которая занимается их чтением. Вот исходник этой функции: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/DoctrineExtensions.php#L35
Схема тут довольно сложная, но если разобраться, вот как выглядит построенная иерархия:
Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain
- AnnotationDriver // тот что создается в registerAbstractMappingIntoDriverChainORM
--CachedReader
---AnnotationReader
- AnnotationDriver // работает с папкой с твоими сущностями
-- CachedReader
--- AnnotationReader
Как видишь, тут мы вместо одного AnnotationDriver создаем цепочку из 2, один нацелен на папку DoctrineExtensions/../Entity, другой на твои сущности.
AnnotationDriver это штука которая читает и анализирует аннотации прописанные например в классе FileResource, кеш там стоит чтобы не делать это на каждый запрос, а только первый раз.
Я посмотрел папку DoctrineExtensions/lib/Tree/Entity, там всего один класс AbstractClosure, я думаю, если ты его не используешь (и если тебе нужно только расширение Tree) то эта цепочка тебе не требуется. Но в качестве упражнения, пожалуй, стоит ее реализовать. Можешь вынести это в отдельную функцию в bootstrap.php
Не забудь что там надо везде передать выбранный нами драйвер кеша, а не то что функции подсовывают по умолчанию.
Посмотри исходники упомянутых функций и разберись как создается эта цепочка.
От тебя требуется создать описанную выше иерархию.
Смотрим код примера дальше.
>// general ORM configuration
> $config = new Doctrine\ORM\Configuration;
Это как я уже написал выше, делается при вызове Setup::createAnnotationMetadataConfiguration и потому не нужно. От нас требуется лишь передать в нужное место созданный выше DriverChain с 2 драйверами аннотаций. Так как функция createAnnotationMetadataConfiguration не позволяет задать драйвер (она создает его сама), то мы от нее отказываемся и заменяем на Setup::createConfiguration после чего ставим в качестве драйвера аннотаций нашу DriverChain.
> $sluggableListener = new Gedmo\Sluggable\SluggableListener;
> $loggableListener = new Gedmo\Loggable\LoggableListener;
> $timestampableListener = new Gedmo\Timestampable\TimestampableListener;
Тут расширения добавляют свои обработчики событий (то есть они будут вызываться например после загрузки сущности из БД или перед сохранением). так как мы не используем эти расширения то можно их не добавлять.
> $treeListener = new Gedmo\Tree\TreeListener;
А вот это нужно, так как мы его используем.
Ну вот и все, то есть реально нужно сделать только 2 вещи:
— сделать цепочку из 2 annotation driver (реально не нужно, но в качестве управжнения стоит сделать)
— добавить обработчик событий от расширения Tree в доктрину
Ну а далее изучай как исопльзуется Tree. Во-первых, ты должен разметить свою сущность, пометив используемые для реализации дерева поля с помощью аннотаций:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md#tree-entity-example
Во-вторых, расширение добавляет в репозиторий дополнительные методы для работы с деревом:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md#using-repository-functions
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/doc/tree.md#repository-methods-all-strategies
Насчет выбора стратегии:
> Пока решил делать комменты просто средствами доктрины как adjacency list,
Не пойдет. Такие комментарии нельзя эффективно выбирать. Почитай май урок, по моему materialized path для комментариев идеален, быстрая вставка и быстрая выборка в уже отсортированном виде.
> чтоб передать parentId в форму, мне нужно обязательно прикручивать jQuery, или этому есть альтернатива?
Есть такие альтернативы:
- чистый JS/DOm без jQuery
- если ты не силен в JS то можно для начала сделать просто радиокнопки перед каждым комментаием, выбирающий parentId. Радиокнопки средствами CSS можно превратить в кнопку «ответить» и заодно сделать подсветку выбранного комментария.
В перспективе надо бы сделать кнопку «ответить» которая через JS вставляет форму, заполняет в ней parentId, а затем аяксом отправляет. На случай пробелм с JS хорошо бы предусмотреть неаяксовую отправку если не сработал JS-код или если он отключен.
Не забудь при отправке аякс-запроса блокировать форму и обрабатывать сетевые ошибки с возможностью повторить попытку. Не забудь валидацию комментария на сервере и вывод списка ошибок. Если грамотно это спроектировать, то для обработки аякс- и не-аякс отправки можно использовать один и тот же код с парой ифов (для аякса например он отдает ответ в JSON, а при неаяксовой отправке делает редирект на страницу с комментариями).
Если какие-то вопросы или уточнения, спрашивай.
А, если тебя вдруг интересует, почему все так сложно и почему у нас 2 класса, AnnotationDriver + AnnotationReader (да еще и кеш посередине), а не один? Потому что доктрина позволяет описывать маппинг разными способами: в аннотациях, в XML, в YML и потому нам нужны разные Reader для разных форматов.
Ну и я тебе советую почитать код расширения:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/Tree/TreeListener.php
Как видишь он при разных событиях вызвыает разные методы у выбранной для сущности стратегии. Вот например стратегия для MPath:
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/Tree/Strategy/ORM/MaterializedPath.php
https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/Tree/Strategy/AbstractMaterializedPath.php
Вот например довольно сложный код вычисления нового path при вставке и обновлении сущности: https://github.com/l3pp4rd/DoctrineExtensions/blob/master/lib/Gedmo/Tree/Strategy/AbstractMaterializedPath.php#L272
По идее чтобы реализовать MPath расширению tree надо лишь отслеживать изменение сущностей, и вычислять для них правильные path/level перед сохранением (правда ситуация становится сложнее когда у нас большой набор сущностей с изменениями, добавлямых и удаляемых сущностей — возможно в таких случаях расширение может что-то неправильно посчитать). Удаление детей при удалении родителя, как я понимаю, делается за счет Foreign KEy в базе по parentId.
Вообще, я вижу у тебя много классов, пора бы забудываться о том чтобы их по папкам раскладывать, сделать неймспейсы и PSR-4.
Ну и хорошо что ты придумываешь свой фреймворк, у нас это ок, но в реальных задачах не изобретай велосипеды и бери готовое.
> function addGetParameterToQueryString($parameter, $value, $queryString = null)
Что-то какие-то костыли пошли в ход. Почему бы не собирать URL с нуля вместо того чтобы разбирать и добалять параметры?
Лучше либо собирать URL с нуля либо передавать в пагинатор шаблон вида index.php?p={page} и подставлять число в него.
И разумеется функцию надо не в bootstrap.php, а в отдельный файл положить или сделать класс Util со статическими методами.
> $container = new Container(new PDO($dsn, $username, $password, $options));
Я думаю, PDO лучше не передавать, а создавать внутри контейнера, в функции GetPdo, а то все объекты кроме него создаются внутри.
> public function trySave(Abiturient $abiturient, Validator $validator)
я думаю что валидатор уместнее передавать через конструктор, как и маппер, так как он нужен в одном экземпляре, сколько бы мы студентов не проверяли.
> // Ограничение потенциально бесконечного цикла.
Что будет если не удалось подобрать уникальный токен с 5 попыток? Твой код почему то замалчивает ощибку как будто бы все в порядке. это непраивльно. Ты должен выбрасыват исключение в таких слуаях иначе никто не узнает о проблеме, пока у тебя половина базы не будет забита неправильными данными. Чем раньше ты обнаружишь проблему тем проще будет ее исправлять.
Не скрывай и не игнорируй ошибки.
> public function getToken($isNew)
Мне не нравится параметр isNew, Это по сути 2 разных функции (получение или генерация токена) и не надо объединять их в одну. Это только запутывает код.
> public function fillFieldsWithValues(Abiturient $abiturient, array $values = array())
Это наверно должно быть в классе Abiturient, так как данные в себя он может сам проставить.
> const SURNAME = "surname";
Я думаю, это лишнее, не надо поля в БД (и поля объекта) объявлять константами. Можно передавать их как просто имена (по крайней мере я не видел чтобы так делали)
> foreach ($abiturient as $property => $value) {
Стоит сделать отдельную функцию, которая преобразует массив из БД в объект-студента.
> = "SELECT COUNT .... LIMIT 1";
LIMIT 1 не имеет смысла так как COUNT это аггрегирующая (объединяющая строки) функция и без GROUP BY она вернет ровно 1 строку.
> public function getAbiturients($orderBy, $orderTrend)
Ты вставляешь переменные в запрос, надо сделать их проверку по списку разрешенных значений. Иначе это SQL инъекция.
> public function search($string, $orderBy, $orderTrend)
Алгоритм поиска переусложнен. Я бы предложил сделать так:
- получаем массив со списком id (не с полным набором полей) по каждому слову.
- объединяем массивы id через array_intersect, оставляя только те id которые встречаются везде
- выбираем объекты через функцию вроде getByIds с сортировкой и пагинацией если массив id не пуст
Ну и конечно есть альтернативные варианты. Во-первых, можно попробовать настроить в msyql FULLTEXT поиск:
http://www.mysql.ru/docs/man/Fulltext_Search.html
Раньше он был только в MyISAM, в новой mySQL он есть ии для InnoDB. Он не позволяет искать по середине или правой части слова.
Во-вторых, мжно искать через LIKE по склееным вместе полям, но это не позволяет искать слова в любом порядке, так что лучше оставить твой вариант.
> public function getPaginator($perPage, array $abiturients = array())
Мне кажется пагинатор незачем класть в контейнер. В контейнере мы храним объекты которые должны быть в одном экземпляре, а пагинаторов может быть много (если на странице выводится несколько таблиц например).
Пагинатор потому надо создавать через new. Это не сервис, а лишь модель переключателя страниц.
> protected function route($uriPath)
Тут надо выводить страницу 404 если маршрут не найден. Не забудь выдавать правильный статус через header(). Я бы советовал выдачу страницы 404 поместить например в базовый контроллер так как на практике бывает надо ее выдавать из не-фронт контроллера.
> $abiturients = $paginator->getCurrentPageContent();
Не, так не пойдет. Надо из базы брать то, что надо, через LIMIT. Я думаю, это не задача пагинатора, а маппера, задача пагинатора лишь отображать номера страниц.
> if ($paginator->numOfPages > 1) {
> $paginationSet = $paginator->getPaginationSet(3);
Если if не сработает, переменной не будет существовать. Это ведет к ошибкам и такого не должно быть, засунь в нее null хотя бы. А если подумать, эта переменная вообще не нужна так как мы можем перенести этот if прямо в шаблон.
> public function getCurrentPage()
> return isset($_GET['page']) ? intval($_GET['page']) : 1;
Работу с GET лучше вынести в контроллер, это его задача, а номер в пагинатор правильнее передавать извне. А то вдруг нам надо не из GET взять номер, а откуда-то еще.
> protected function render(Abiturient $abiturient, $errors)
Это приемлемо, но довольно громоздко, на практике шаблонизаторы обычно получают на вход имя шаблона + массив переменных:
$this->render('teplate.twig', [
'a' => $a,
'b' => $b
]);
Но можно оставить и твой вариант.
> if ($birthyear > 1999 || $birthyear < 1901) {
Обижаешь 15-летних юных гениев.
Кстати мне кажется лучше вместо проверки года вычислять возраст и отсеивать по нему. А то через 5 лет твой код начнет отсеивать 20-летних. Это недальновидно.
> error_reporting(-1);
> mb_internal_encoding('utf-8');
> define("SITE_ROOT", __DIR__);
Это стоит тоже в bootstrap перенести
> .myform
если не знаешь как назвать css-класс, используй назвние приложения: abiturient-form
> <link href= "../style/style.css" rel="stylesheet">
Эта ссылка хрупкая так как она зависит от текщего URL. Если ты добавишь несколько сегментов например:
/student/list/by-name/page/1
То она будет указывать совсем в другое место (/student/list/by-name/style/stуle.css)
Стоит завести параметр в конфиге rootUri который определяет корень сайта (напрмиер / или /students) и подставлять его в путь к css- файлам.
> <li class="<?=parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == "/" ? "activ
Шаблон не должен лезть в SERVER, передавай имя текущего пункта из контроллера.
> <strong>Успешно!</strong><br/> <?=$flashMessage;?>
Неплохо бы CSS/HTML подучить. Это оформляется как h3 + ul/li для каждой ошибки либо h3 + p если сообщение одно.
> $service = $this->container->getAbiturientService();
Шаблон не должен лезть в DI контейнер.
> foreach ($errors as $key => $value) {
Я думаю лучше этот foreach перенести в alert_warning.html.php и используовать версию с доветочием:
<?php foreach ... ?>
<p>...</p>
<?php endforeach ?>
Форму бы надо оформить. Ты используешь бутстрап, почему бы не сделать как там принято:
http://getbootstrap.com/css/#forms
Использование <br> так часто как у тебя верный признак что человек не знает HTML/CSS.
> <a href="<?=$paginator->getNextPageLink();?>" aria-label="Next">
Все выводимые данные надо пропускать через htmlspecialchars
например & в ссылках должен выводиться как & по правилам HTML.
Функции надо вынести из шаблона в отдельный файл. Можно сдеолать класс ViewHelper со статическими методами.
В таблице надо бы показыать текщуее направление сортировки. Например, подсвечивая треугольничек или заголовок.
Так, вообще неплохо, но пока еще есть что дорабатывать.
Вообще, я вижу у тебя много классов, пора бы забудываться о том чтобы их по папкам раскладывать, сделать неймспейсы и PSR-4.
Ну и хорошо что ты придумываешь свой фреймворк, у нас это ок, но в реальных задачах не изобретай велосипеды и бери готовое.
> function addGetParameterToQueryString($parameter, $value, $queryString = null)
Что-то какие-то костыли пошли в ход. Почему бы не собирать URL с нуля вместо того чтобы разбирать и добалять параметры?
Лучше либо собирать URL с нуля либо передавать в пагинатор шаблон вида index.php?p={page} и подставлять число в него.
И разумеется функцию надо не в bootstrap.php, а в отдельный файл положить или сделать класс Util со статическими методами.
> $container = new Container(new PDO($dsn, $username, $password, $options));
Я думаю, PDO лучше не передавать, а создавать внутри контейнера, в функции GetPdo, а то все объекты кроме него создаются внутри.
> public function trySave(Abiturient $abiturient, Validator $validator)
я думаю что валидатор уместнее передавать через конструктор, как и маппер, так как он нужен в одном экземпляре, сколько бы мы студентов не проверяли.
> // Ограничение потенциально бесконечного цикла.
Что будет если не удалось подобрать уникальный токен с 5 попыток? Твой код почему то замалчивает ощибку как будто бы все в порядке. это непраивльно. Ты должен выбрасыват исключение в таких слуаях иначе никто не узнает о проблеме, пока у тебя половина базы не будет забита неправильными данными. Чем раньше ты обнаружишь проблему тем проще будет ее исправлять.
Не скрывай и не игнорируй ошибки.
> public function getToken($isNew)
Мне не нравится параметр isNew, Это по сути 2 разных функции (получение или генерация токена) и не надо объединять их в одну. Это только запутывает код.
> public function fillFieldsWithValues(Abiturient $abiturient, array $values = array())
Это наверно должно быть в классе Abiturient, так как данные в себя он может сам проставить.
> const SURNAME = "surname";
Я думаю, это лишнее, не надо поля в БД (и поля объекта) объявлять константами. Можно передавать их как просто имена (по крайней мере я не видел чтобы так делали)
> foreach ($abiturient as $property => $value) {
Стоит сделать отдельную функцию, которая преобразует массив из БД в объект-студента.
> = "SELECT COUNT .... LIMIT 1";
LIMIT 1 не имеет смысла так как COUNT это аггрегирующая (объединяющая строки) функция и без GROUP BY она вернет ровно 1 строку.
> public function getAbiturients($orderBy, $orderTrend)
Ты вставляешь переменные в запрос, надо сделать их проверку по списку разрешенных значений. Иначе это SQL инъекция.
> public function search($string, $orderBy, $orderTrend)
Алгоритм поиска переусложнен. Я бы предложил сделать так:
- получаем массив со списком id (не с полным набором полей) по каждому слову.
- объединяем массивы id через array_intersect, оставляя только те id которые встречаются везде
- выбираем объекты через функцию вроде getByIds с сортировкой и пагинацией если массив id не пуст
Ну и конечно есть альтернативные варианты. Во-первых, можно попробовать настроить в msyql FULLTEXT поиск:
http://www.mysql.ru/docs/man/Fulltext_Search.html
Раньше он был только в MyISAM, в новой mySQL он есть ии для InnoDB. Он не позволяет искать по середине или правой части слова.
Во-вторых, мжно искать через LIKE по склееным вместе полям, но это не позволяет искать слова в любом порядке, так что лучше оставить твой вариант.
> public function getPaginator($perPage, array $abiturients = array())
Мне кажется пагинатор незачем класть в контейнер. В контейнере мы храним объекты которые должны быть в одном экземпляре, а пагинаторов может быть много (если на странице выводится несколько таблиц например).
Пагинатор потому надо создавать через new. Это не сервис, а лишь модель переключателя страниц.
> protected function route($uriPath)
Тут надо выводить страницу 404 если маршрут не найден. Не забудь выдавать правильный статус через header(). Я бы советовал выдачу страницы 404 поместить например в базовый контроллер так как на практике бывает надо ее выдавать из не-фронт контроллера.
> $abiturients = $paginator->getCurrentPageContent();
Не, так не пойдет. Надо из базы брать то, что надо, через LIMIT. Я думаю, это не задача пагинатора, а маппера, задача пагинатора лишь отображать номера страниц.
> if ($paginator->numOfPages > 1) {
> $paginationSet = $paginator->getPaginationSet(3);
Если if не сработает, переменной не будет существовать. Это ведет к ошибкам и такого не должно быть, засунь в нее null хотя бы. А если подумать, эта переменная вообще не нужна так как мы можем перенести этот if прямо в шаблон.
> public function getCurrentPage()
> return isset($_GET['page']) ? intval($_GET['page']) : 1;
Работу с GET лучше вынести в контроллер, это его задача, а номер в пагинатор правильнее передавать извне. А то вдруг нам надо не из GET взять номер, а откуда-то еще.
> protected function render(Abiturient $abiturient, $errors)
Это приемлемо, но довольно громоздко, на практике шаблонизаторы обычно получают на вход имя шаблона + массив переменных:
$this->render('teplate.twig', [
'a' => $a,
'b' => $b
]);
Но можно оставить и твой вариант.
> if ($birthyear > 1999 || $birthyear < 1901) {
Обижаешь 15-летних юных гениев.
Кстати мне кажется лучше вместо проверки года вычислять возраст и отсеивать по нему. А то через 5 лет твой код начнет отсеивать 20-летних. Это недальновидно.
> error_reporting(-1);
> mb_internal_encoding('utf-8');
> define("SITE_ROOT", __DIR__);
Это стоит тоже в bootstrap перенести
> .myform
если не знаешь как назвать css-класс, используй назвние приложения: abiturient-form
> <link href= "../style/style.css" rel="stylesheet">
Эта ссылка хрупкая так как она зависит от текщего URL. Если ты добавишь несколько сегментов например:
/student/list/by-name/page/1
То она будет указывать совсем в другое место (/student/list/by-name/style/stуle.css)
Стоит завести параметр в конфиге rootUri который определяет корень сайта (напрмиер / или /students) и подставлять его в путь к css- файлам.
> <li class="<?=parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == "/" ? "activ
Шаблон не должен лезть в SERVER, передавай имя текущего пункта из контроллера.
> <strong>Успешно!</strong><br/> <?=$flashMessage;?>
Неплохо бы CSS/HTML подучить. Это оформляется как h3 + ul/li для каждой ошибки либо h3 + p если сообщение одно.
> $service = $this->container->getAbiturientService();
Шаблон не должен лезть в DI контейнер.
> foreach ($errors as $key => $value) {
Я думаю лучше этот foreach перенести в alert_warning.html.php и используовать версию с доветочием:
<?php foreach ... ?>
<p>...</p>
<?php endforeach ?>
Форму бы надо оформить. Ты используешь бутстрап, почему бы не сделать как там принято:
http://getbootstrap.com/css/#forms
Использование <br> так часто как у тебя верный признак что человек не знает HTML/CSS.
> <a href="<?=$paginator->getNextPageLink();?>" aria-label="Next">
Все выводимые данные надо пропускать через htmlspecialchars
например & в ссылках должен выводиться как & по правилам HTML.
Функции надо вынести из шаблона в отдельный файл. Можно сдеолать класс ViewHelper со статическими методами.
В таблице надо бы показыать текщуее направление сортировки. Например, подсвечивая треугольничек или заголовок.
Так, вообще неплохо, но пока еще есть что дорабатывать.
Ну так бери и делай задание, там подробные комментарии есть. Это если ты знаешь ООП и прошел нащ учебник, если нет то начинай с ООП и можешь еще другие задачки из учебника порешать.
>>515646
Можно показывать всем, но как только кто-то за нее берется, блокировать ее на N минут так что второму открыть отчет не получится.
>>515665
Это маловероятно, Zend большой фреймворк. На оф сайте есть доки на русском в том числе.
>>515785
мы не одобряем и не обсуждаем создание спамботов тут. Хорошему товару и услугам не нужна спам-реклама, она нужна только лузерам которые купили какую-нибудь никому не нужную фигню и не могут продать ее даже по себестоимости.
К счатстью, госорганы не дремлют и периодически наказывают любителей тратить чужое время.
А на западе за спам вообще сажают. Так-то.
>>515846
Троллишь? еды не будет тут, это не /b тут 2 с половиной анона всего сидят.
Спасибо за очередную простыню.
>> const SURNAME = "surname";
>Я думаю, это лишнее, не надо поля в БД (и поля объекта) объявлять константами. Можно передавать их как просто имена (по крайней мере я не видел чтобы так делали)
>
Ну я исходил из того, что в таблице могут появиться новые поля, что названия этих полей нам могут потребоваться где-то в другом месте, и не факт, что объект абитуриента будет иметь соответствующее свойство. А ещё названия полей таблицы могут поменяться. И придётся по всему коду их заменять.
В моём приложении это действительно, наверное, лишняя заморочка, но как решаются такие проблемы в реальных задачах? И возникают ли?
> <link href= "../style/style.css" rel="stylesheet">
>Эта ссылка хрупкая так как она зависит от текщего URL. Если ты добавишь несколько сегментов например:
>/student/list/by-name/page/1
>То она будет указывать совсем в другое место (/student/list/by-name/style/stуle.css)
>Стоит завести параметр в конфиге rootUri который определяет корень сайта (напрмиер / или /students) и подставлять его в путь к css- файлам.
>параметр в конфиге rootUri
Ты про что-то вроде этого: define("SITE_ROOT", __DIR__) ?
Оно у меня есть в index (ты сказал в bootstrap перенести. Кстати, а почему бы не оставить его в индексе? __DIR__ там тот, который нам нужен, т. к. индекс в корне сайта лежит, а в bootstrap придётся прописывать вручную).
С остальными замечаниями всё понятно, исправлю.
>Ты про что-то вроде этого: define("SITE_ROOT", __DIR__) ?
Туплю, это же путь в файловой системе.
Для rootUri подобную константу объявить в bootstrap?
> В моём приложении это действительно, наверное, лишняя заморочка, но как решаются такие проблемы в реальных задачах? И возникают ли?
Лучше сразу назвать поля правильно. Потому что единственный способ потом их поменять это поиск и замена по всему коду. Константы вряд ли решение так как очень неудобно в каждый запрос их вставлять.
>>516044
Почему константу? переменную наверно лучше.
>Почему константу?
Ну в процессе выполнения скрипта этот самый rootURI не меняется же.
В константу собираюсь записать вытащенную из глобального массива нужную нам часть адреса.
Почему в spl_autoload_register() передаётся массив, хотя в документации такого нет?
Почему в аутпуте есть эти строки:
>Class1::__construct()
>Class2::__construct()
?
А как понять, что душа лежит к кодингу, а не к заманчивым перспективам стать финансово успешным? Я вот начал учить из-за того, что меня интересует зп в 1+ к вечнозеленых и не нужно мне лечить про то, что это враки, я лично знаю 3-х, которые получают от 1к до 1.5к на пыхе, не будучи сеньорами. Но в процессе понял, что меня прет писать проекты, особенно, когда не начинаешь писать, а заканчиваешь и окидываешь взглядом строки кода, кликаешь по интерфесу и все работает, все клево, но вот сидя дома я не могу себя заставить что-то писать, играю в игори, читаю книжки, а писать влом. Получается работаю только под прессом - НАДА, то есть пришел дядя тимлид сказал пиши сука и я пишу, и мне нравится, но как только заданий нет, мне фиолетово становится. Лежит ли у меня душа к кодингу или нет и мне стоит покинуть всю эту херню?
Я этим вопросом уже год мучаюсь. Пздц.
Массив это способ сделать ссылку на метод объекта. В PHP есть несколько способов передать ссылку на функцию, массив один из них:
http://php.net/manual/ru/language.types.callable.php
http://habrahabr.ru/post/259991/
http://habrahabr.ru/post/147620/
> Почему в аутпуте есть эти строки:
В конструкторе класса стоит echo, может в коде его забыли добавить.
Ну они правы. Если все через силу учишь и из под палки делаешь, то не пойдет. А если определенное удовольствие получаешь во время процесса изучения очередной технической поебени, то нормально, можно работать.
Если у тебя душа не лежит то работа надоест тебе через несколько месяцев/лет (мотивация от получения денег проходит через месяц-два) и ты сам с нее уйдешь. Ну или будешь мучаться.
https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php
Я не понимаю, вроде же все правильно настроено, почему я получаю ошибку "The class 'Uppu3\Resource\FileResource' was not found in the chain configured namespaces Gedmo, Entity"
ОП, посмотри пожалуйста, я уже с этим бутстрапом с ума схожу, я попроходил по всем функциям, почитал весь затрагиваемый код, но все-равно не понимаю какого хрена оно не работает. Я наверно еще ни с одной проблемой так долго безвыходно не бился.
>Zend большой фреймворк. На оф сайте есть доки на русском в том числе.
На рутрекере книгу от индуса нашел:
http://rutracker.org/forum/viewtopic.php?t=4663386
Сейчас по ней пробую, вроде проще оф. документации.
> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L30
Что тут значит Entity? Если посомтреть на прототип функции то это
public function addDriver(MappingDriver $nestedDriver, $namespace)
(кстати если тебе интересно как я нашел функцию: я в пустой папке создал composer.json, и прописал в него доктрину, после чего сделал composer install, послу чего перетащил папку vendor в sublime, после этого по Ctrl + Shift + R можно перейти к любой функции и классу из доктрины).
Вместо Entity надо указать твой неймспейс для сущностей. Тебе даже в сообщении об ошибки об этом пишется.
Ну и не бойся лезть в код той же доктрины и смотреть что не так. Ты можешь даже var_dump туда напихать (только не забудь удалить потом).
Мдя, я думал Entity это имя аннотации, поставил свой неймспейс, вернулся к старым баранам
"[Semantical Error] The annotation "@Entity" in class Uppu3\Resource\FileResource was never imported. Did you maybe forget to add a "use" statement for this annotation?"
Аннотации это не просто абстрактные имена. Аннотации это имена классов. Например аннотация @Entity соответствует классу
http://www.doctrine-project.org/api/orm/2.2/source-class-Doctrine.ORM.Mapping.Entity.html#26
Как ты видишь, свойства этого класса соответсвутют опциям, которые можно указывать в скобочках после Entity.
Посмотри файл по ссылке.
А раз это классы то для них действуют те же правила и надо указыват use c именем неймспейса.
Обычно пишут
use Doctrine\ORM\Mapping;
>Аннотации это не просто абстрактные имена. Аннотации это имена классов. Например аннотация @Entity соответствует классу
Ну это я понял, но это все-равно мне не объясняет что не так в моем бутстрапе. Извини, может я уже очень сильно торможу, но сейчас я не могу понять что не правильно в моем бутстрапе, и почему доктрина не может прочитать @Entity в FileResource.
Потому что надо написать либо use либо полное имя класса вместо Entity. Потому что его полное имя это \Doctrine\ORM\Mapping\Entity
Все-равно, я не понимаю, почему здесь
http://doctrine-orm.readthedocs.org/en/latest/reference/basic-mapping.html
в примерах нету ничего о том что нужно использовать use Doctrine\ORM\Mapping?
Ну и опять же, сделав так как ты говоришь, получил новую ошибку "Class "Uppu3\Resource\FileResource" is not a valid entity or mapped super class."
Ладно, буду биться головой об стенку и гуглить дальше, может таки на меня снизойдет озарение, а то у меня уже начинает закрадываться подозрение что я тупой
Действительно, в примерах нет use. Может там какая-то опция есть которая позволяет без него обходиться?
Но тут например оно есть: http://doctrine-common.readthedocs.org/en/latest/reference/annotations.html
Если посмотреть, там есть опция http://doctrine-common.readthedocs.org/en/latest/reference/annotations.html#default-namespace которая задает неймспецс по умолчнаию — видимо ты ее откючил когда переделывал конфигурацию доктрины.
Вот еще ответ вроде бы по теме: http://stackoverflow.com/a/15108579 — там дело в том что есть 2 разных reader.
> Ну и опять же, сделав так как ты говоришь, получил новую ошибку "Class "Uppu3\Resource\FileResource" is not a valid entity or mapped super class."
Стоит посмотреть где эта ошибка выдается и что именно проверяется, в исходниках доктрины.
http://stackoverflow.com/questions/7820597/class-xxx-is-not-a-valid-entity-or-mapped-super-class-after-moving-the-class-i
Судя по этому посту причина может быть в том что у тебя нет корректной аннотации @Entity
Я уже в принципе понял, если использовать $annotationReader = new Doctrine\Common\Annotations\AnnotationReader;
то use нужен, а если
$annotationReader = new Doctrine\Common\Annotations\SimpleAnnotationReader;
то нет.
Ну и весь стэковерфлоу я уже пересмотрел, все эти решения видел и сверял со своим классом, вроде ошибок у себя я не вижу, entity проставлен. Надо бы порыть в сторону доктрины, посмотреть на чем у меня ошибка вылетает.
А не может быть такой что этот экстеншонс нормально работает с доктриной версии 2.1, а с 2.5 такие проблемы?
Потому что я
Вряд ли дело в версии.
Насчет "Class "Uppu3\Resource\FileResource" is not a valid entity or mapped super class." можешь попробовать очистить (или временно отключить, заменив на ArrayCache) кеш, может там что осталось. Иногда очистка кеша делает чудеса.
Насчет кэша ты прав, поменял, помогло - теперь у меня другая ошибка "[Semantical Error] The annotation "@Doctrine\ORM\Mapping\Entity" in class Uppu3\Resource\FileResource does not exist, or could not be auto-loaded."
Вернусь к этому вопросу со свежей головой. Блин, за целый день так и не сделал ничего полезного, и походу не продвинулся вообще в понимании этого вопроса, пичалька
Алсо хотят memcached/nginx и оптимизацию для высокопроизводительных вебсайтов, где про это читнуть вообще?
столько пердолинга и ради чего? Я только из-за этого и не ставлю себе linux и им не обмазываюсь, ибо пока не будешь знать как все работает и чувствовать себя как бог - всякая работа будет адом. Пердолинг - вообще какая то ихняя философия. Хочешь поставь на свою убунту очередную ебу - будь добр прочитай талмуд по йобе, 2-3 дня попердолся и в конце узнай, что кретины написавшие йобу криворукие пидарасы.
Компьютерные сети как в целом написаны? Я танненбаума "архитектура ПК" читаю, мне кажется простым и логичным все. Если так, то норм будет.
От программистов для программистов же. При разработке постоянно с какими-нибудь кривыми либами и такими же кривыми доками к ним ебешься. После тяжелого рабочего дня приходишь домой, включаешь пеку, а там все то же самое, только уже в операционке.
Начал я делать одно задание из сайта в ОП-посте. Вроде все норм и особых проблем изначально не наблюдалось.
Но потом появилась одна функция. В эту функцию я передаю одно значение. И данное значение в функции мне нужно использовать как индекс массива.
Так вот, конструкция вида
> $bill = 100;\t\t\t\t\t\t\t\t\t
> echo $bills[$bill] . "\n";
вне функции работает нормально. Но как только я пытаюсь запилить вот это:
> function checkBills ($bill) {\t\t\t\t\t\t
> echo $bills[$bill] . "__";
> и так далее...
происходит некоторое дерьмо. В частности echo благополучно выводит "__" и все. А при умножении данного значения в функции на любое число получается нуль.
Есть у меня подозрение, что я что-то пропустил в теории, только вот что я так и не нашел. В общем хз, помогите что ль.
Вот сам ...кхм код http://ideone.com/Dfx6JB.
Так же буду рад любым замечаниям по поводу кода.
Смотри что написано внизу страницы http://ideone.com/Dfx6JB
> PHP Notice: Undefined variable: bills in /home/unuKY0/prog.php on line 21
> PHP Notice: Undefined variable: amout in /home/unuKY0/prog.php on line 22
> PHP Notice: Undefined variable: bills in /home/unuKY0/prog.php on line 22
> PHP Notice: Undefined variable: amout in /home/unuKY0/prog.php on line 28
> PHP Notice: Undefined variable: amout in /home/unuKY0/prog.php on line 29
> PHP Notice: Undefined variable: amout in /home/unuKY0/prog.php on line 29
Видишь сколько ошибок? Неудивительно что не работает.
Внутри функции не видны переменные которые созданы снаружи (глобальные). Ты должен явно их передавать как аргументы.
Глянул содержание, ощущение что книга написана скорее для чистых сетевиков или сисадминов, хуй знает читать или нет. Разве что просто чтобы лишний раз повыебываться.
Попробовал, работают оба варианта
preg_match('/\d+\w+/',$searchstring,$matches);
preg_match('/\\d+\\w+/',$searchstring,$matches);
var_dump($matches); выдает для обоих идентичный результат.
Вариант с двумя слешами универсален. Не нужно задумываться над тем, какой и когда ставить.
>> public function getAbiturients($orderBy, $orderTrend)
>Ты вставляешь переменные в запрос, надо сделать их проверку по списку разрешенных значений. Иначе это SQL инъекция.
Но ведь эти переменные могут содержать только константы, перечисленные в маппере: https://github.com/blackberryJam/abiturients/blob/master/app/classes/MainPageController.php#L11
Кстати, что скажешь насчёт такого способа защиты от инъекций?
Проверка переменной должна стоять там, где она втавляется в запрос то есть в функции getAbiturients
Там ее нет, значит человек должен искать все места где вызывается эта функция по всему коду и анализировать как обраьатываются параметры. Так не пойдет. Ни я, ни кто-то еще не захочет это делать. Я хочу чтобы сразу было видно безопасна функция или нет.
Ну и даже если у тебя параметр где-то в другом месте проверяется нет никаких гарантий что завтра ты не вызовешь функцию из другого места. где эти параметры не проверяются.
Потому должна быть проверка в функции getAbiturients.
> Кстати, что скажешь насчёт такого способа защиты от инъекций?
Это не защита. Функция вставляет данные прямо в запрос и нет гарантий что завтра кт-ото не впишет вызов который не проверяет их.
Чаще для разбора HTML/XML, иногда и для создания.
>>516799
Разница есть когда надо найти бекслеш регуляркой. Тогда ты должен писать его 4 раза:
\\\\
По правилам регулярок для поиска бекслеша надо написать его ровно 2 раза: \\ . Но PHP интерпретирует \\ в строке как один бекслеш, и движок регулярок получит только один бекслеш. Потому их надо написать 4 штуки.
Вот это тут описано: http://php.net/manual/ru/language.types.string.php#language.types.string.syntax.double
Также когда ты хочешь найти знак доллара, придется наставить бекслешей. По правилам регулярок ты должен вписать \$ но с учетом обработки строк PHP придется написать "\\\$" для строки в двойных кавычках и '\\$' для строки в одинарных.
Это все из-за того что PHP обрабатывает escape-последовательности при чтении программы и движок регулярок получает уже обработанную стрку.
Ты можешь увидеть это поведение с помощью echo:
echo "\\\\ \\\$"; выведет \\ \$
1. Сделай iframe-виджет который умеет подстраивать свои размеры под содержимое. Ну например на сайте a.example.com мы подключам JS код с b.example.com который создает ифрейм и загружает в него например список новостей. Как ты знаешь, размер ифрейма задается снаружи, а нам надо чтобы после загрузки списка новостей ифрейм подстроил свой размер (высоту), чтобы они отображались без прокрутки. Он должен это делать за счет обмена сообщениями с яваскриптом на странице, передавая ему команды изменить размер ифрейма.
Не забудь проверять источник сообщений.
2. Сделай iframe-widget-плеер (плеер разумеется можно взять готовый например любой jquery player плагин, лучше с поддержкой HTML 5 audio). Ты подключаешь один и тот же iframe на одной или нескольких страницах в разных вкладках браузера, эти iframe находят друг друга. После этого в любом из них при нажатии воспроизведения все остальные ставятся на паузу. Также изменения громкости в одном плеере действует на все остальные.
Такой механизм полезен не только для плеера. Преставь что пользователь открыл несколько страниц соцсети. По умолчанию каждая из них устанавливает отдельное соединение с сервером чтобы узнавать о новых сообщениях, лайках и тд и отображать уведомления. Но если эти вкладки могут находить друг друга то они могут поручить получение уведомлений только одной из них. Это снижает нагрузку на сервер. разумеется, надо понимать что пользователь может в любой момент закрыть вкладку-мастер, в этом случае оставшиеся страницы должны выбрать нового мастера.
В первой задачке на функции (про айпад) из учебника http://archive-ipq-co.narod.ru/l1/functions.html
Так как кредит без первого взноса, надо как-то хитро учесть проценты и комиссию за первый взнос, верно? Я просто ничего не смыслю в этих кредитах, экономику в универе прогуливал.
http://pastebin.com/kyR66dcT-Djn Вот это сырой вариант, объясните мне кто-нить, почему у меня PHPStorm ругается на пробел после круглых скобок после for??
Твоя ссылка на pastebin не открывается (пишут что код удален).
Там первый взнос просто длается добавлением его в самом начале к сумме долга. То есть ты берешь кредит на 39999 и должен уже 39999 + 7777. И с этой суммы начинается отсчет.
Каждый месяц на долг добавляется процент (от текущей суммы долга) и фиксированная комиссия. После этого анон платит, проходит месяц и все повторяется.
И ещё один вопрос, есть несколько прог которые автоматически регистрируют в каталогах, собственно интересно как это у них получается? Каталогов сайтов очень большое количество и все они по разному сделаны, не писать же парсер для каждого? Или все они по одинаковому сделаны и есть какие-то общие АПИ в которые можно закинуть адрес сайта, выбрать категорию, ключевые слова и всё остальное в автоматическом режиме?
Если у них есть АПИ, то есть смысл попробовать написать скрипт который будет проверять насколько живой тот или иной каталог сайтов. То есть загружаешь файл со списком (урлами) каталогов, проверяешь каждый и возвращаешь уже файл только с теми которые реально работают.
Нет, решил именно подтянуть знание DOM.
Провайдер тебя забанит. Юзай бесплатного или прокси.
>Каталогов сайтов очень большое количество и все они по разному сделаны, не писать же парсер для каждого?
Как раз и пишут для каждого. Там писать не особо много, всего-то форма добавления url и пара возможных ответов сервака. Но когда их много ,то дохуя выходит, да, поэтому эти проги за бабло обычно и продают. API общего нет.
А куда тогда идти? На Java и C# работы нет, на Python и Ruby тоже мало... 1C что ли учить?
> и без того короткой профессиональной жизни программиста
Проиграл что-то. Ну прямо спортсмен или фотомодель ваш программист, такая карьера короткая, да.
В миллионниках полно работы на жабах и .net, на рыбе тоже есть. Еще можно в низкоуровневое уйти на C или C++, или программирование игр на Unity и UE. Если работа есть только на пыхе, лучше съехать с этого мухосранска.
Мне бы хоть на пхп научиться кодить, остальные языки слишком сложные, я довольно глупый.
>> function addGetParameterToQueryString($parameter, $value, $queryString = null)
>Что-то какие-то костыли пошли в ход. Почему бы не собирать URL с нуля вместо того чтобы разбирать и добалять параметры?
Мне надо добавлять параметры, если их значение не установлено. А если установлено -- менять на новые. Чтобы собрать URL с нуля, пагинатору придётся узнавать о том, для какой страницы (просто выдачи или же поиска) он формирует ссылки. Не выходит ли это за пределы его задач?
Эта же функция у меня используется и в шаблоне, при формировании сортировочных кнопок-ссылок.
>передавать в пагинатор шаблон вида index.php?p={page} и подставлять число в него.
Значение подставлять просто конкатенацией?
Если у нас там уже есть какие-то get-переменные, как их сохранить, не разбирая запрос на части и не собирая потом вновь?
Функция была изначально создана мной для того, чтобы реализовать переход между страницами без потери настроек сортировки.
Чтоб не искать, сама функция вот: https://github.com/blackberryJam/abiturients/blob/master/app/bootstrap.php#L23
Factory (фабрика) это класс, который создает другие объекты. Идея примерно такая, что при исплоьзовании new мы не можем повлиять на то, объекты какого класса и как создаются:
public function doSmth()
{
return new SomeClass;
}
Если эту функцию написали не мы, то повлиять на нее мы не можем.
В случае создания объектов через фабрику, мы можем передать другую фабрику и повлиять на то как создаются объекты:
public function _ _ construct(Factory $factory)
{
$this->factory = $factory;
}
public function doSmth()
{
return $this->factory->createSomeObject();
}
Вот в википедии схема есть: https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%B0%D1%8F_%D1%84%D0%B0%D0%B1%D1%80%D0%B8%D0%BA%D0%B0_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
На практике это редко когда нужно так как сильно усложняет код.
И еще, если ты пытаешься заучить паттерны (например к собеседованию), то ты занимаешься глупостью. Чтобы понимать эти паттерны, надо чтобы ты сталкивался с кодом который их использует (либо может использовать). Если у тебя нет особого опыта работы с ООП-кодом, ты паттерны просто не поймешь.
Так что если хочешь изучать паттерны, для начала посиди поковыряйся в коде Симфони например.
Factory (фабрика) это класс, который создает другие объекты. Идея примерно такая, что при исплоьзовании new мы не можем повлиять на то, объекты какого класса и как создаются:
public function doSmth()
{
return new SomeClass;
}
Если эту функцию написали не мы, то повлиять на нее мы не можем.
В случае создания объектов через фабрику, мы можем передать другую фабрику и повлиять на то как создаются объекты:
public function _ _ construct(Factory $factory)
{
$this->factory = $factory;
}
public function doSmth()
{
return $this->factory->createSomeObject();
}
Вот в википедии схема есть: https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%B0%D1%8F_%D1%84%D0%B0%D0%B1%D1%80%D0%B8%D0%BA%D0%B0_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
На практике это редко когда нужно так как сильно усложняет код.
И еще, если ты пытаешься заучить паттерны (например к собеседованию), то ты занимаешься глупостью. Чтобы понимать эти паттерны, надо чтобы ты сталкивался с кодом который их использует (либо может использовать). Если у тебя нет особого опыта работы с ООП-кодом, ты паттерны просто не поймешь.
Так что если хочешь изучать паттерны, для начала посиди поковыряйся в коде Симфони например.
Тролль незаметен.
>>517116
сео лучше обсуждать в /web, мы тут программированием занимаемся.
>>517374
> Чтобы собрать URL с нуля, пагинатору придётся узнавать о том, для какой страницы (просто выдачи или же поиска) он формирует ссылки. Не выходит ли это за пределы его задач?
Ну так сейчас ты передаешь querytring, а будешь передавать массив параметров, не много и поменяется. Или передавай шаблон ссылки.
> Значение подставлять просто конкатенацией?
заменой {page} на число.
> Если у нас там уже есть какие-то get-переменные, как их сохранить, не разбирая запрос на части и не собирая потом вновь?
При замене ничего не теряется. Ну или ты можешь передавать массив параметров.
>>517403
Это в 2 словах не объяснишь. Надо правильно распределить память для mysql, натсроить индексы, переписать неудачные запросы.
Кое-что есть тут:
http://ruhighload.com/post/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0+%D1%81+%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0%D0%BC%D0%B8+%D0%B2+MySQL
http://www.mysql.ru/docs/man/MySQL_indexes.html
http://habrahabr.ru/post/211022/
Тролль незаметен.
>>517116
сео лучше обсуждать в /web, мы тут программированием занимаемся.
>>517374
> Чтобы собрать URL с нуля, пагинатору придётся узнавать о том, для какой страницы (просто выдачи или же поиска) он формирует ссылки. Не выходит ли это за пределы его задач?
Ну так сейчас ты передаешь querytring, а будешь передавать массив параметров, не много и поменяется. Или передавай шаблон ссылки.
> Значение подставлять просто конкатенацией?
заменой {page} на число.
> Если у нас там уже есть какие-то get-переменные, как их сохранить, не разбирая запрос на части и не собирая потом вновь?
При замене ничего не теряется. Ну или ты можешь передавать массив параметров.
>>517403
Это в 2 словах не объяснишь. Надо правильно распределить память для mysql, натсроить индексы, переписать неудачные запросы.
Кое-что есть тут:
http://ruhighload.com/post/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0+%D1%81+%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0%D0%BC%D0%B8+%D0%B2+MySQL
http://www.mysql.ru/docs/man/MySQL_indexes.html
http://habrahabr.ru/post/211022/
у меня есть несколько блоков, в которых есть изображения, эти блоки формируются на основе данных из бд.
Так вот, мне хотелось бы иметь возможность посчитать количество изображений в каждом из блоков и в зависимости от этого менять их размер.
$('.изображение').length показывает количество всех изображений, но как найти конкретно в каждом из блоков?
Но он по ходу устарел.
Вот тут проблема: http://phpclub.ru/mysql/doc/loading-tables.html
Создаю файлик со значения полей, чтобы не вбивать ручками(у меня в качестве разделителя ";"). Чтобы подставить NULL в поле death, пишу \n в нужных местах. Получается такой файл.
Fluffy;Harold;cat;f;1993-02-04;\N
Claws;Gwen;cat;m;1994-03-17;\N
Buffy;Harold;dog;f;1989-05-13;N
Fang;Benny;dog;m;1990-08-27;\N
Bowser;Diane;dog;m;1998-08-31;1995-07-29
Chirpy;Gwen;bird;f;1998-09-11;\N
Whistler;Gwen;bird;\N;1997-12-09;\N
Slim;Benny;snake;m;1996-04-29;\N
У автора все получилось, и заместо \N вставилось NULL, у меня и других парней с форума, на котором я искал решение другой проблемы с этим примером тоже самое(последний пост, там в конце почемуто NULL присутствует): http://sqlinfo.ru/forum/viewtopic.php?id=4087
То есть вместо NULL значение становится 0000-00-00, через select NULL вставляется. Я хз, что тут делать. Нет я могу забить все руками и пойти по мануалу дальше(так и сделаю пока), но хочу разобраться.
http://ideone.com/Chstwl
http://ideone.com/yddJ6y
http://ideone.com/xgdIm2
http://ideone.com/gmkUEV
изучающий-SQL-анон
По идее так
<?php
echo "Добро пожаловать в рулетку\n";
$random = mt_rand(100000,999999);
echo "Номер поста $random\n";
$lastDigit=$random %10;
if ($lastDigit==6){
\techo "Поздравляю ты шестерка\n";
}elseif ($lastDigit==7){
\techo "Блатной да?\n";
}else {
\techo "Ты мужик";
}
1. Это легитимный тред? Если нет, то киньте линк.
2. В общес, освоил основы пыхи, джс, джиквери, мускуль, теперь пора учить, то, что принесет мне трудоустройство и соответственно профит. План такой - делаю как говорят, в прочессе учусь\разбираюсь и следующим делаю уже свой проект. Вот решил по этому гайду заниматься https://github.com/githubjeka/yii2-tutorial
Кто что думает, особенно ОП, что можешь сказать после беглого взгляда.
http://ideone.com/xoYyhz
Может кто - нибудь подсказать что я сделал не так? Только начал учить, и застрял.
Вы видите копию треда, сохраненную 13 августа 2015 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.