Это копия, сохраненная 14 июня 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме. ОПу ведь все это читать придется.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Предыдущий тред был тут: >>966608 (OP) ( http://arhivach.org/thread/254710/ )
Еще предыдущие треды ищутся в гугле по словам "клуб php" или в архиваче. Еще есть такой архив тредов: http://phpclub.rf.gd/
Мейлач лежит? Есть запасной тред: доброчан-орг/s/res/23225.xhtml#i46467
Что самое главное для программиста? Умение аккуратно оформлять код (читай второй пост, прежде чем писать код).
Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка PHP, этого недостаточно. Вот что в идеале надо изучить еще: ООП, как работает веб-сервер, HTML/CSS, SQL, PDO, работа с таблицами в БД, работа с формами, MVC, git, composer, JS, фреймворки, автоматизированное тестирование.
Надо переходить к более серьезным задачкам, которые научат тебя всему этому.
- для начала прочти урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- установи Апач + PHP (советы выше и ниже) и читай туториал http://php.net/manual/ru/tutorial.php
- Учи HTML/CSS и SQL, PDO, хотя бы основы
- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Symfony: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование https://gist.github.com/codedokode/a455bde7d0748c0a351a
- Если ты все решил, переходи к Symfony 2/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://github.com/codedokode/pasta/blob/master/db/databases.md
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.
Платиновые вопросы
- Почему PHP? Потому что фейсбук и википедия на нем написаны, и вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/.
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Посоветуйте редактор кода - Sublime Text 3, Notepad++, PhpStorm
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
- Что самое главное для программиста? Умение аккуратно оформлять код.
- ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
- Подскажи сайты для поиска работы, я не умею гуглить? — hh.ru, geekjob.ru, moikrug.ru (склеен с brainstorage.me), fl.ru, upwork.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/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Давай удочку, а не рыбу
Лучше не давать готовое решение проблемы, а рассказать как его искать. Может дать ключевые слова для гугла или ссылку. Но помогай, а не пытайся показать превосходство. Если даешь ссылки на нерусскоязычные статьи, упомяни об этом.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию 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/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
------------------
Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.
Давай удочку, а не рыбу
Лучше не давать готовое решение проблемы, а рассказать как его искать. Может дать ключевые слова для гугла или ссылку. Но помогай, а не пытайся показать превосходство. Если даешь ссылки на нерусскоязычные статьи, упомяни об этом.
Будь доброжелателен
Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»
Не придирайся к знанию английского или русского языка.
Объясняй
Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»
Не проповедуй
Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.
Не придирайся к знанию английского языка, анон пишет как умеет.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
>изучать C
эта дорога точно не ведет в веб. ЦС50 тоже, это достаточно общий курс по компутер-саенс, если новичок, то будет довольно интересно, может быть и передумаешь вкатываться в веб.
>>988894
Очевидный курс от ОПа, начни с задач по ООП из учебника http://archive-ipq-co.narod.ru/
Ну по идее, толстым у тебя контроллер получается если ты слишком много всяких операций проводишь в контроллере. В таком случае подумай над тем, что бы распихать все эти операции по отдельным ф-ям/методам. В идеале у тебя контроллер должен только принимать данные от пользователя(http запросы, куки, сессии, формочки ну ты понел) и передавать их в модель с минимальной обработкой, ну там еще валидация всякая, ну и принимать от модели и отдавать вьюшке, как-то так.
Спасибо, котики
Он уже 15 лет как ВСЕ.
https://github.com/some-random-username/student-list
https://pastebin.com/XBFzDwsY с шапки общетреда взял.
Что кроме книг по js, php, html нужно? Абсолютный нуфаг без базы
Делай по книге на юкозе из шапки.
>>988868 (OP)
Только вкатываюсь, по образованию - гуманитарий. Как же это охуенно сделать свой рандомнамбер генератор (первое задание с кубиком).
Мельком поглядел. У тебя в классе с запросами в базу, много методов с почти похожими селектами. Можно сделать один метод, а запрос сделать сделать составным. К примеру, если в качестве условия ты ничего не передал, то строка "WHERE id = ?" не будет подставляться в запрос. Класс будет больше, и сложнее. Но, если грамотно сделать, то у тебя получится один класс, который делает одну функцию - делает селект в базу.
Сорян. Не класс, а метод будет сложнее и выполнять одну функцию.
Еще небольшой совет дам, хотя это вкусовщина.
Чтобы избежать высокого уровня вложенности, вроде как в методе match роутера, можно использовать условия от обратного. То есть не "if (azaza) { чтото делаем }", а "if (!azaza) { return; } чтото делаем" как пример.
1. Хорошо что ты задумываешься о контейнере зависимостей, однако вряд ли ты до конца понимаешь как им пользоваться. Например, ты делаешь отдельный класс для соединения с БД, хотя по логике очевидно что это тоже зависимость. Сам контейнер - имхо далеко не лучшая идея возвращать зависимость как элемент массива, лучше сам объект и возвращай. Алсо, советую почитать про интерфейс PSR - 11 и посмотреть как устроен контейнер Pimple.
2. По части контроллеров пока заметил только одно грубое нарушение - ты не экранируешь данные. Нельзя просто принимать данные в виде $_GET["something"], это серьезная уязвимость. Почитай про XSS, ОП-а где-то было об этом.
3. В индексном файле советую автозагрузку и прочее распихать по отдельным файлам, так будет удобней редактировать.
4. В моделях ты тоже наговнокодил. Ты не правильно назвал класс для работы с таблицей студентов, из название выходит что это у тебя модель сущности студента, а по факту это шлюз к таблице, переименуй на StudentsTableGateaway. Исходя из того что я про контейнер написал - надеюсь тебе понятно почему твой класс Model не нужен. То как ты выбираешь студентов из базы - это вообще путь в никуда. Читай больше про работу с PDO и выбирай одним запросом всех студентов в специально созданный класс-модель с соответсвующими полями. И это, я так и не понял зачем ты прямо так делаешь пагинацию.
5. Дальше не читал, еще добавлю что стоит все таки комментировать свой код если ты собираешься его кому-то показывать, я вот на работе сижу и особо времени разбирать твой код нет. Прокоментируй и вечером еще посмотрю.
Данные в контроллере экранировать не требуется. И если экранировать, то для чего? для вывода? Для использования в SQL запросе? Экранировать данные надо там, где они используются.
>Данные в контроллере экранировать не требуется.
ИМХО лучше таки в контроллере, что бы в моделях меньше мороки было.
Ты по моему плохо понимаешь, что такое экранирование. Ты наверно начитался плохих учебников, где учат, что данные от пользователя "опасные" и их надо "очистить" (пропустить через несколько случайно выбранных функций), чтобы они стали "безопасными" (ага, святой водой полить).
Но это неправильно. Данные сами по себе не "опасные" и их нельзя "очистить". Уязвимости возникают при неправильном использовании данных - например вставке их напрямую в SQL-запрос вместо использования плейсхолдеров. Или при выводе данных в HTML-коде без применения htmlspecialchars. Или при попытке подключить файл, имя которого задается пользователем.
Ну и я не понимаю, где тут логика - данные используются в одном месте кода, а экранируются где-то далеко в другом. А как тогда проверить, что они надежно экранированы? Изучать весь код и тщательно проверять, какая переменная куда передается? И это ведь не защитит от того, что завтра кто-то допишет вызов функции, передав ей неэкранированные данные.
>Ты по моему плохо понимаешь, что такое экранирование. Ты наверно начитался плохих учебников, где учат, что данные от пользователя "опасные" и их надо "очистить" (пропустить через несколько случайно выбранных функций), чтобы они стали "безопасными" (ага, святой водой полить).
Может быть, в данном случае я просто имел ввиду очистить от html-тегов, лол.
>И это ведь не защитит от того, что завтра кто-то допишет вызов функции, передав ей неэкранированные данные.
Тут как бы логика в том, что если у тебя одна точка приема данных от пользователя, т.е. контроллер, то лучше бы там хотя бы от тегов почистить, а то мало ли макак которая модуль пишет забудет это сделать.
Тут нет логики. Почему очищать именно от HTML-тегов (то есть по сути угловых скобок)? А что насчет других символов, вроде точек, запятых, вертикальных палочек, вьетнамской письменности и десятков других символов Юникода?
Ты невнимательно прочел мой пост. Я написал, что данные не могут быть "опасными" сами по себе и их "почистить" нельзя. Можно только создать видимость безопасности таким образом.
>Тут нет логики. Почему очищать именно от HTML-тегов
Самый общий случай же. В БД сомнительно что бы кто-то сейчас вставлял данные без подготовленных запросов
Понял, спасибо. Сейчас попробую переделать. >>989133
>Получение параметров запроса в модели?
Да, совсем не заметил. То есть обязательно надо передавать параметры запроса из контроллера в модель?
>>989177
>Сам контейнер - имхо далеко не лучшая идея возвращать зависимость как элемент массива, лучше сам объект и возвращай.
Так я же вроде объекты и возвращаю.
>return new \src\models\StudentsModel($container['db']);
Или я тебя не так понял?
>посмотреть как устроен контейнер Pimple.
Я как раз с него и пытался делать.
>По части контроллеров пока заметил только одно грубое нарушение - ты не экранируешь данные. Нельзя просто принимать данные в виде $_GET["something"], это серьезная уязвимость. Почитай про XSS
Но ведь потом я эти данные вывожу через htmlspecialchars в шаблоне.
>Ты не правильно назвал класс для работы с таблицей студентов
Да, с моделью все совсем плохо вышло. Увидел ошибки, спасибо.
Только я сначала хотел через сущности сделать, но не понял, как вывести, например, список всех студентов. Там же под каждую запись в таблице отдельный класс нужен.
Отдельный класс не под каждую запись в табилце, а под каждую таблицу ты хотел сказать. Ну так со шлюхом так же. А вот инстансы класса под каждую запись, это да в AR. Например список записей таблицы должен быть представлен в виде коллекции объектов AR.
А вообще AR тема не сложная.
>Так я же вроде объекты и возвращаю.
Я посмотрел, ты там юзаешь ArrayAcces, тогда все норм должно быть.
> Там же под каждую запись в таблице отдельный объект нужен
Так и должно быть.
Кастомные типы гугли
https://ideone.com/eedOFR
При ничье выбивает это:
Игрок бросает кость. Выпало: 6.
Игрок бросает кость. Выпало: 3.
Компьютер бросает кость. Выпало: 5.
Компьютер бросает кость. Выпало: 4.
Сумма очков игрока: 9.
Сумма очков компьютера: 9.
Очки игрока и компьютера равны. Счет - 9.
Не понял.
>А вообще AR тема не сложная.
В теории не сложная, а на практике реализовать ее новичку довольно непросто. Для меня сразу пару непонятных моментов появилось по теме active record, которые я смогу понять только на реальных примерах.
Я вот сел сейчас переделывать и понял, что лучше сначала попробовать изучить пару фреймворков и сделать на них 2-3 сайта, а уже потом свои ошибки будут очевидны.
1×1 = 1
2×2 = 4
...
9×9 = 81
Ты можешь взять пример кода с картинки ниже за основу."
Хули оно такое сложное?
Да, охуеть сложное для нуба, когда после ссаного elseif идут сразу циклы, которые даже по мнению php.net - самое сложное в пхп.
Там пиздят.
Циклы - это самые основы основ.
Он тебе алгоритм расписал, по которому это можно понять. Хуль выебываешься?
ideone.com/LDqB9c
"произведение", я ебу что это? Прохожу по гайду из шапки
>Требуемые знания: умение включать компьютер и пользоваться браузером. Ноутбук/айпад/планшет/смартфон тоже подходят, если в них есть интернет.
https://ideone.com/LDqB9c
И как я должен был это понять идя по гайду? Это нихуя не объяснялось.
"пример" про опа-молодца нихуя не помогал.
И да, если идти по его "алгоритму" то получается хуита.
<?php
for(;$i<10;){
$sum=$i$i;
echo "$i$i=$sum\n";
}
?>
Алгоритм, с которым мне "помогли" (по факту помог только намёк про $sum) - https://ideone.com/TOCegr
Алгоритм, который должен быть - https://ideone.com/LDqB9c
>>989438
Умножение. Звездочку двощ считает за курсив.
Где ты оправдания видишь то? Я лишь посетовал на то, что подсказка была не особо ЛЕГИТИМНА, и несла в себе ошибку решил за тебя, впрочем, ничего нового. Единственная помощь, полученная от подсказки - использовать переменную в к-ве производной.
И решение мне не нужно было, мне нужен был лишь толчек в нужном направлении. Решения оставьте для школьников, пусть они радуются что их проблему кто-то там решил, потом дойдет что важность знания - научиться решать эту проблему, а не готовое решение.
Я бы дропнул программирование и застрелился, если бы мои потуги так раскритиковали. Но я и половины не понял из того что там написано
Нормально сделал? Что не так мб? Делал не по примеру немного.
Никто ничего не критиковал, просто показали как можно сделать лучше, значит увидели потенциал, иначе не тратили бы время на анализ и на стену текста
Теперь понятно.
я к вам из JS треда
он тоже начинал базовую хуйню делать, а потом понеслось
Я на этом палиндроме и айфоне застрял. Все равно не мог их сам решить
Я когда сам его решать пытался, сделал все тоже самое практически, только буквы по другому брал. Думал, что нужно взять с первого символа по середину $halfLength и с последнего до середины и сравнить их. Но в итоге хуйня выходила.
Я надеюсь это была одна из самых сложных задач в пхп ?
Ну подскажите, горит пиздец.
боюсь, вам больше не стоит заниматься пограмированием.
чето ты реально нагородил, делай расчет суммы в цикле и считай года в нем же
Ня :3
>Просто не понимаю даже в какую сторону идти.
Это совсем просто, тебе нужно идти в сторону хуя, очевидно же
Всё-равно нихуя не получается.
http://archive-ipq-co.narod.ru/i/php-noob-14.png
Зачем в этом примере {$i} в фигурных скобках?
https://ideone.com/nevOI1
<?php
$age=16;
$start=10000;
$perc=1.1;
$money=$startX$perc;
for($start=10000;$money<1000000;$money=$startX$perc){
echo "$money\n";
}
В цикле фор, соответственно с гайдами и прочей хуйней.
Start - со скольки стартует. Действие 1, выполняется разово. Начинается с 10000. Условие - пока startXperc не дойдут до миллиона. Действие2 - пока условие не выполнено - должен умножать стартовые 10к на 1.1. Но оно не хочет лупить. Что за хуйня?
кто-нибудь работу нашел? Я тут учил кодинг где-то с 2014, ща работаю фронтендером в ДС.
Скоро ты будешь рыдать.
Говорю тебе как 33летний редактор в издательстве, который вот уже два года бьётся во всём этом.
Но у меня мечта (одна из), к которой приближаюсь с каждым днём, - свой проект. Сейчас в нём треть частично реализована программистом за деньги, частично мной самим.
Такое окрыляет, придаёт силы.
Это пройдет за несколько лет работы и множество реализованных проектов, как своих, так и чужих. Вот не спеша для души поковырять код - это дело. А въебывать это, конечноо, изматывает даже в этом деле.
Да, полностью согласен.
Но имею в виду, что нужно очень хотеть научиться, без этого никак.
Я вот только пару месяцев как не вижу фигу, когда смотрю в чужой код, начинаю довольно быстро соображать, что к чему.
Практика, постепенное освоение, пропускание через себя всех задач - это всё нужно.
Ладно давай. Уже вкатился или только в планах ? За хеллоу волд пояснить сможешь ?
В 2012-м изучил HTML+CSS на достаточном уровне, потом освоил Wordpress. Сделал с тех пор кучу сайтов, часть из которых продал, а часть по-прежнему приносит какую-то копейку на партнёрских программах.
Так что именно в программирование не совсем с нуля вкатился, получается, общие представления имел.
>>989675
Пару братишек помню и старше меня, только потом отсеялись куда-то.
Ну а так можно ещё и в нашей уютной конфе сидеть: https://t.me/PHP_club (только я вряд ли на выходных смогу).
Экранировать переменную.
>>989627
Блядь ты вообще ничего не понимаешь сука нахуй.
>>989646
Ладно, тут я порвался.
https://ideone.com/zdvG0d
В данный момент допиливаю один из проектов на бету, чтобы хоть немного с чистой совестью потом поебланить (сроки уже на неделю всрал, заказчик ворчит).
По деньгам выше среднего в моем городе, с фрилансом и подработками раза в 3 повыше наверно, но ничего заоблачного, черную икру не жру. Работу менять лень сейчас, сила привычки. Вордпрессы всякие даже не видел никогда, брезгую. Выговорился.
>>989681
А че у вас в конфе интересного происходит?
А вот с образованием хреново. С первого курса пидорнули, поэтому среднее профессиональное.
Сам только что про это написать хотел.
Конечно. Там есть опытные люди, ну и так своими силами что-то думаем обычно.
>>989698
Ну отлично же, если есть работа и возможность развиваться.
В конфе есть Карасик, который с 1С перешёл сейчас для разнообразия на РНР, иногда бывает. В целом там у нас больше по существу разговоры, чем за жизнь, но никто не против и просто поболтать.
Ну так реши уже задачу ебана в рот, и покажи нам что ты понял.
>>989710
>Объясн
1 раз в жизни сталкивался с тем где это было нужно, но уже нахуй забыл. Проще погуглить.
Вообще это нужно для того, что бы более сложные переменные компилятор точно воспринимал как переменные
То есть ты можешь хуярить вместо:
echo "Имя пользователя: " . $user->userName;
Такую поебень прямо в строке:
echo "Имя пользователя: {$user->userName}";
Словил макконахи и опустились руки. Чем больше узнаю, тем больше себя чувствую на дне, но даже там слышу, как снизу стучат. Иногда думаю, что я создан только сидеть под деревом и созерцать, а не заниматься интеллектуальным трудом.
Хуй знает, может перерыв надо сделать и вообще к пеке не прикасаться месяц другой, хотя бы дома, ведь я на работе 8 часов за пекой, после неё все за пекой, заебался столько инфы через себя пропускать. Но с другой стороны, пока я отдыхаю - двадцатилетний делает то, что я за год не успеваю.
Чет я приуныл.
Репортнул дауна
Я вам прямо завидую. Вы вроде нуфаги, но вам норм, гитхабчиками светите. Я не нуфаг, но у меня на гитхабе такая параша, которую просто жалко выкидывать (архив кода мой по сути), что я его сам с дрожью открываю.
Ну а про дно - границы познания это.
Работаю на фулл-тайм работе за еду 5/2. Подумаю об этом, когда изучу пик, допилю AphorismCMS и еще какую-нибудь поделку, сделаю задачи из оппоста. Есть риск сдаться раньше. Считаю, что пока не выхожу на уровень джуна, к тому же живу мухосранске (Краснодар), пытаюсь копить деньги на перекат. Фриланс не потяну.
А меня пугает, что я такой нуфаг, что даже твои проекты мне кажутся сложными и крутыми
О, я начинал читать эту книгу, но не осилил в итоге. Некоторые моменты показались слишком непонятными и оторванными от реальности (но я месяца два всего изучаю пхп, поэтому все дело во мне).
>Считаю, что пока не выхожу на уровень джуна
Но ты же отлично понимаешь, что уровень джуна у тебя уже давно есть. Зачем принижаешь себя?
Вроде, тут только я один такой социоблядь, больше не видел чтобы кто-то светил. Да и у меня тоже это архив кода. Без гитхаба все превращается в свалку, которую только удалить хочется.
>О, я начинал читать эту книгу, но не осилил в итоге.
Так я её с января изучаю, по моему, и только 2/3 прошел. Очень медленно, прерываясь на свои поделки. Я до неё еще пытался вкатится в ООП и MVC. Каждый раз, когда возвращался к своим поделкам, то юзал что-то оттуда. Мне она дается тяжело, главу про шаблон Интерпретатор 10 раз перечитывал.
Возможно, мой уровень достаточен для двадцатилетнего джуна на третьем курсе, но не двадцатисемилетнего лба с заборостроительным дипломом.
не деанонте, плез
Не, не пытался. Вообще не интересует это.
https://ideone.com/HMUOFw
Я решил. Мой затуп был в $money=$money*$percent. Как прикрутить floor к $money? Не хочет округлять вниз.
Что сделать чтобы ебаный школьник не переплачивал?
Условие цикла неверное, хотя тебе это пока не принципиально.
Условие внутри цикла не верное, из-за него все и ломается. Почему то 3000 вместо 5000, 3% вместо 103%, да и вообще не то.
Условие лучше.
Еще раз объявляеть $leftToPay не нужно.
Условие < 5000 должно быть внутри цикла, а не за ним. Само условие тоже поправить. Добавить внутрь логики.
Если ты пошел путем $month*$monthlyPayment, то лучше это сразу в конец цикла пихать (перед бриком) с соответсвующей надбавкой, чем считать каждый раз.
Вывод окончательного результата можно сделать уже после цикла.
Компилятор тебе черным по белому написал, что ты использовал break вне цикла или свича, что должно было заставить тебя обратить внимании на его положение в коде. Учись слушать ошибки.
>Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492
>PhpStorm — жми Ctrl+Alt+L
Он переводит открывающую конструкцию скобку { после класса и функции на новую строку, а после условий не перевод. ЛИБО ПЕРЕВОДИТЬ, ЛИБО НЕТ. Нахуя совмещать?
Засунул Собакину в $_SESSIONS['last_name'], достал Собакину на другой странице $last_name = $_SESSIONS['last_name'].
И ПОЛУЧИЛ ВОПРОСИКИ)))
Я просто за сегодня порвался с таких нелепых проблем.
Кругом выставил header("Content-Type: text/html; charset=utf-8"); Даже маме своей позонил и сказал: "ХЕАДЕР ЧАРСЕТ УТФ-8".
Скачал нотепад, проверил BOM, НИГДЕ НЕТ ЕГО, НИ НА ОДНОЙ БЛЯДСКОЙ СТРАНИЦЕ. Пхп-сторм не даёт удалить BOM, потому что его НЕТ.
СТАРТ
<?php
session_start();
В самой первой строке, самого первого файла, фронт-котроллер, что бы ты не делал - всё начинается с него.
Потушите мою Собакину.
Ты успокойся и проверь, в какой кодировке сохранен файл с исходным кодом программы - должно быть utf-8 без BOM.
И при чем тут русский язык? utf-8 он не для русского языка придуман, а вообще для всех языков. Это ненормально в наше время ограничивать себя латинницей, когда есть прекрасные письменности с тысячами иероглифов.
>>989959
Так в PSR-1, 2 и требуется. Почитай https://svyatoslav.biz/misc/psr_translation/
>Ты успокойся и проверь, в какой кодировке сохранен файл с исходным кодом программы - должно быть utf-8 без BOM.
>
>И при чем тут русский язык? utf-8 он не для русского языка придуман, а вообще для всех языков. Это ненормально в наше время ограничивать себя латинницей, когда есть прекрасные письменности с тысячами иероглифов.
У меня приступ, потому что я 3 час а убил на поиск решения и не нашёл его.
Пруф из нотепада.
Да проблема в том, что он не готов, осталось чуть-чуть, как будет готово - всё на гих вывалю или вообще на бесплатный хостинг залью, что бы нагядно. Это всё студенты ебучие. Осталось поиск сделать(кодировку выебать) и сортировку, на пару часов дел(mySql даётся не очень).
Есть один css фреймворк PURE, в нем интересуют только кнопки https://purecss.io/buttons/
Почему на оф странице кнопки в высоту 34 px, а когда подключаешь на свою страницу, то кнопки 38 px?
И с помощью какой магии между кнопками на оф сайте получается отступ?
там сложно (
нахуя?
Способы работы с формами давно уже изучены. Не изобретай велосипеды, а читай мои уроки (или чьи-нибудь другие на ту же тему): https://github.com/codedokode/pasta/blob/master/forms.md
Ну и у тебя опять видна проблема с непониманием MVC и неумением разделять ответственность. Ты все пишешь одной функцией authorAdd(), но гораздо удобнее сделать отдельную функцию валидации и отдельную функцию сохранения в БД. Ты берешься за сложное приложение, но при этом ты пишешь код в том же стиле, как пишут простые скрипты на 20 строчек. Это нужно исправлять.
Понятно, что можно и с плохим кодом сделать что-то работающее, но я не понимаю, какая в этом выгода. Ты ведь наверно хочешь научиться чему-то, но делая кое-как, ты в итоге ничему не научишься. Лучше остановиться и разобраться.
> чтобы вместо списка форма на ходу предлагала варианты
берешь плагин вроде Chosen или Select2 и прикручиваешь к нему получение вариантов дополнения через аякс либо через заложенный в коде список (если у тебя мало вариантов, то лучше просто список в HTML коде заложить).
>>990088
По поводу оформелния - попробуй просто убрать центрирование текста на всей странице, сразу станет лучше.
>>990156
Если тебе не хочется, можно наверно и не изучать.
Я ценю твои советы, много полезного почерпнул и подтянул уровень. Но вот бомбит меня от того, что ты меня каким то дауном неоубучаемым выставляешь.
Действительно, так же пишут простые скрипты на 20 строчек? В том же стиле, серьезно? В прошлый раз я вообще прожег стул от ПОЛНОЕ НЕПОНИМАНИЕ MVC. Я, конечно, тоже считаю, что прогресс измеряется не количеством просиженных часов за доками, но вот я вижу как писал раньше https://github.com/grigoryMovchan/appsForStore и как пишу сейчас и считаю, что это небо и земля. До твоего уровня как до Луны пешком, но развитие, не без помощи в этом треде, определенно прослеживается.
Я и так понимаю, что хуйней какой-то донной занимаюсь. Зачем специально то еще дизморалить. Кому от этого польза?
Зря я отправил, удалил бы, будь возможность. Стыдно теперь.
Я тут мимо пробегал, но хотел спросить по этому коду
1) возможен рейс-кондишон, всем похуй?
2) что там с обработкой исключений в пыхе, можно хуй класть?
Зачем обрабатывать исключения в этой функции? Если в SQL запросе синтаксическая ошибка, что ты можешь сделать? Ничего, только ждать пока программист придет и исправит ее.
Вообще, по моему опыту в 95% случаев исключения ловить не надо. Надо только в редких случаях - например, когда мы хотим сделать повторный HTTP-запрос при ошибке или что-то такое.
Тебе надо не спешить делать новые фичи, а остановиться и разобраться с существующим кодом. Какой смысл в том, что я тебе указываю на ошибку, а ты продолжаешь писать код с этими ошибками? Больше исправлять ведь придется.
Ты мой урок по MVC читал? Вот видимо невнимательно читал.
Вот есть допустим задача - добавить нового автора. Вот у меня переменная с его именем.
Есть ли у тебя функция в модели, которая решает эту задачу? Фактически нет, твой код непригоден для решения этой задачи.
И это говорит о том что никакого MVC у тебя нету. Ты не прочел внимательно мой урок про MVC, не сделал разделение кода, а просто сделал классы "Модель", "контроллер", "вид" и думаешь что теперь у тебя MVC код. А по факту в твоей "модели" обычная стена кода, где все вперемешку. И которую нельзя ни тестировать нормально, ни повторно использовать.
Прочитай урок, серьезно, прочитай. Там ведь даже пример кода есть. Чтобы твой код соответствовал MVC, нужно, чтобы у тебя была функция, которая позволяет добавить автора. Чтобы можно написать, например:
$something->addAuthor('Лев Толстой');
При добавлении автора может произойти ошибка (например, такой автор уже есть). Раз так, то нам конечно хочется еще иметь функцию, которая бы сказала нам, можно добавить такого автора, или нет.
Также, ты используешь неудачный подход для возврата результатов (в функции addAuthor). Вот смотри, есть какая-то функция, которая что-то возвращает. Ну например, сумму 2 чисел:
$result = sum(2, 2); // вернет 4
А у тебя сделано по сути так:
sum(2, 2);
$result = getSumResult();
То есть ты вместо того, чтобы вернуть результат функции через return, используешь какие-то обходные пути и изобретаешь велосипеды.
И смешиваешь в одном классе функцию добавления автора с функцией хранения уведомлений пользователю. Каждый класс должен заниматься своей задачей. Класс, который работает с таблицей авторов, не должен заниматься накоплением сообщений для показа пользователю.
Вот еще один мой урок, он прямого отношения к твоему коду не имеет, но может быть извлечешь что-то полезное: https://github.com/codedokode/pasta/blob/master/good-code.md
Я советую остановиться и исправить существующий код.
Тебе надо не спешить делать новые фичи, а остановиться и разобраться с существующим кодом. Какой смысл в том, что я тебе указываю на ошибку, а ты продолжаешь писать код с этими ошибками? Больше исправлять ведь придется.
Ты мой урок по MVC читал? Вот видимо невнимательно читал.
Вот есть допустим задача - добавить нового автора. Вот у меня переменная с его именем.
Есть ли у тебя функция в модели, которая решает эту задачу? Фактически нет, твой код непригоден для решения этой задачи.
И это говорит о том что никакого MVC у тебя нету. Ты не прочел внимательно мой урок про MVC, не сделал разделение кода, а просто сделал классы "Модель", "контроллер", "вид" и думаешь что теперь у тебя MVC код. А по факту в твоей "модели" обычная стена кода, где все вперемешку. И которую нельзя ни тестировать нормально, ни повторно использовать.
Прочитай урок, серьезно, прочитай. Там ведь даже пример кода есть. Чтобы твой код соответствовал MVC, нужно, чтобы у тебя была функция, которая позволяет добавить автора. Чтобы можно написать, например:
$something->addAuthor('Лев Толстой');
При добавлении автора может произойти ошибка (например, такой автор уже есть). Раз так, то нам конечно хочется еще иметь функцию, которая бы сказала нам, можно добавить такого автора, или нет.
Также, ты используешь неудачный подход для возврата результатов (в функции addAuthor). Вот смотри, есть какая-то функция, которая что-то возвращает. Ну например, сумму 2 чисел:
$result = sum(2, 2); // вернет 4
А у тебя сделано по сути так:
sum(2, 2);
$result = getSumResult();
То есть ты вместо того, чтобы вернуть результат функции через return, используешь какие-то обходные пути и изобретаешь велосипеды.
И смешиваешь в одном классе функцию добавления автора с функцией хранения уведомлений пользователю. Каждый класс должен заниматься своей задачей. Класс, который работает с таблицей авторов, не должен заниматься накоплением сообщений для показа пользователю.
Вот еще один мой урок, он прямого отношения к твоему коду не имеет, но может быть извлечешь что-то полезное: https://github.com/codedokode/pasta/blob/master/good-code.md
Я советую остановиться и исправить существующий код.
Ну так в этом и суть. Рейс кондишн конкретно в пхп в данном случае - невозможен. На уровне базы и разных процессов пхп возможен. В конкретно данном случае очень вероятно, что невозхможен вообще, ибо все происходящее атомарно просто и достаточно было не проебаться при создании бд. Ну или я тебя в чем-то не понял. В большинстве случаев такие ситуации решаются транзакциями.
Про исключения не согласен с предыдущим, я их не сторонюсь использовать, ловить и обрабатывать. Но в целом это не маст хев, если работаешь с фреймворком, который сам это все умеет и выводит в виде ошибки пользователю.
По идее должен быть обработчик непойманных испключений, который залоггирует его и покажет страницу 503. Но в PHP талантливые архитекторы вместо этого сделали показ белой страницы с кодом 200, а если включен display_errors - еще и с выводом текста ошибки, которую радостно проиндексирует Гугл.
Потому обычно приходится писать свой обработчик непойманных исключений.
Чтобы исключить race condition при вставке существующего автора, можно поставить в БД UNIQUE KEY по полю "имя", тогда попытка вставки существующего автора вызовет исключение.
Транзакция тут никак не помогла бы ибо она группирует запросы на изменение данных, а на SELECT-запросы почти никак не влияет (кроме случаев блокировок SELECT ... FOR UPDATE/LOCK). Вот если бы он вносил несколько изменений то да, желательно использовать транзакцию, чтобы в БД не было частично вставленных данных.
Также, у тебя плохо сделана проверка на уникальность. Если в БД есть автор "Джон" то вставить "Джо" он не даст.
Тогда я тебя не правильно понял и понесло меня.
>Какой смысл в том, что я тебе указываю на ошибку, а ты продолжаешь писать код с этими ошибками?
Ты это зря так думаешь. Я по пунктам все отрабатываю https://github.com/grigoryMovchan/AphorismCMS/blob/master/code_review.txt и многое уже успел переделать.
>>990219
>Вот есть допустим задача - добавить нового автора. Вот у меня переменная с его именем.
>Есть ли у тебя функция в модели, которая решает эту задачу?
>$something->addAuthor('Лев Толстой');
Вот с этим просто не согласен. Нет у меня такой задачи. Я целенаправленно её решил так. Этот "велосипед" конкретная рекомендация из Зандстра и похожим образом сделано в ларавель, только там Request передается не один раз в конструктор, а персонально каждой функции, где он может потребоваться. Захотел попробовать - попробовал. Может потом поумнею и признаю, что был не прав, но пока так.
Да не оч. Матан нужен только если ты какие - то убер алгоритмы пишешь
Пока ты не поработаешь с классами в 900 строк и 30 - 40 методов не поймешь. И переубедить никто не сможет. И писать комменты на англе дурной тон ( к стати если тебе нужны коменты в приделах одного метода - значит ты где - то что то сделал не так )
Нет, скорее если в бд есть автор Джон, то Джонсон - это тоже самое, т.к содержит "Джон". В регулярке нужно добавить ограничители ^ начало строки & конец строки.
Регулярка там вобще не нужна, имя делаеться уникальным индексом. Оп и проверка не нужна
Опчик, а ты сам кем работаешь и какой стаж?
Не рань мне душу, негодяй.
>>990237
> И писать комменты на англе дурной тон
Не понел. Я как раз стараюсь на ангельском все писать, вдруг свалить повезет.
Можно еще посмотреть на exists.
Очапятка на русском :)
> Этот "велосипед" конкретная рекомендация из Зандстра
Какая глава?
Думаю, что Зандстра не будет советовать возлагать на один класс несколько разных задач.
На мой взгляд ты просто делаешь код более неудобным в использовании, сложным в понимании. Посмотри на мой пример с вычислением суммы - какой смысл делать как у тебя, если можно просто вернуть результат?
> и похожим образом сделано в ларавель, только там Request передается не один раз в конструктор,
Ларавель - своеобразный фреймворк, но мне кажется, даже там такого нет. Можешь дать ссылку?
> Вот с этим просто не согласен.
Тогда у тебя не MVC. А ты просто сделал класс с названием "Контроллер" и "Модель". В MVC используется разделение на компоненты, а не пишут все в одном месте. Тогда тебе надо убрать слова вроде "контроллер" или "модель", чтобы не сбивать читателя с толку.
> Нет у меня такой задачи
А задачи реализовать архитектуру MVC тоже нет? Или допустим ты захочешь из командной строки импортировать авторов - как ты будешь делать. Или протестировать, что функция работает - как ты напишешь тест?
А еще нахера ретурнить true или false если можно ретурнить массив с ключами? и строить ответ?
Или можно вообще выбрасывать исключение, ловить их в контроллере и на них него 500 кодом отвечать с текстом ошибки?
>PHP-тред
Впрочем, ничего необычного.
Если ты эту лапшу через месяц прочитаешь так же как и сегодня то да ( и другие люди тоже )
Ничего плохого в этом нет. Была статья лет 50 назад (не помню, может от Дийкстры), но потом нашлись и противоположные мнения.
Тут есть аргументы на англ, кому интересно, можете изучить: http://wiki.c2.com/?SingleFunctionExitPoint (мне лень).
Я считаю, что ничего плохого в нескольких ретурнах нет, наоборот, попытка сделать единственную точку выхода может ухудшить код (например, придется ставить огромные ифы и повышать глубину вложенности).
Так и про return можно сказать. Может сразу тогда скажем - не пишите запутанный код?
>Ларавель - своеобразный фреймворк, но мне кажется, даже там такого нет. Можешь дать ссылку?
Допускаю, что там Request не тот Request, что у меня https://laravel.ru/docs/v5/quickstart-intermediate
>Какая глава?
Сейчас искать не буду. Там смысл был в том, чтобы суперглобальные переменные обрабатывались в отдельном классе, потому что может понадобится сделать с ними что-то спецефическое, и напрямую не передавались в модель.
Ок, я могу получить id из Request в контроллере и передать его в метод модели. А как тогда быть со вторым пиком? Неправильно написан Request и для данных из формы должен быть свой массив, который я должен получать из Request в контроллере и передавать в метод модели?
Ну если так рассуждать то у каждого метода будут свои за и против. И об этом спорить можно вечно просто кому как удобней. Но допустим сколько я не общался с программерами > 5 лет опыта все стараются этого избегать
>>990261
Ну если ты определишь чёткую грань между запутанным и не запутанным кодом то можем и сказать
Но ты реально мог бы сделать имя автора уникальным индексом - тогда бы просто лишился проверки и метода. Пытался бы вставить автора а там уже еxception разруливал если он упал по индексу
Там отдельный уровень абстракции для MySQL. Да, ОП его обоссал и я с ним согласен, но это пока мой уровень. Я его вообще спиздил из урока по авторизации, он был в виде одной функции, на mysqli и без подготавливаемых запросов.
https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Models/MysqlModel.php
"разруливать" exception довольно неудобно, так как там кроме кода проверять нечего. Ну и вдобавок тогда нельзя будет без попытки вставить запись сделать валидацию.
Не понял, как бы я лишился проверки имени на уникальность заюзав индексы?
любимое аниме
На самом деле у него тут простой, пусть и кривоватый, пример того, чем множество return в методе лучше к примеру if {} else if { } else.
Чисто мой вкус мне это нравится визуально, приятно посмотреть, но это чисто визуальщина.
А вот чем такой код чище можно представить исходя из его примера и пресловутого массива errors, потому что для ошибок вообще отлично подходит и находит наиболее частое применение.
Допустим у нас две возможных ошибки в методе, одна следует за другой.
Вариант с ретурнами
if (чтото не так) { $this->errors[] = 'Something wrong'; return;}
if (еще что-то не так) {$this->errors[] = 'Fucking error'; return;}
//тут начинается реальный полезный код
И то же самое без этого подхода.
if (все ок) {
if (и тут все ок) {
//полезный код
} else {
$this->errors[] = 'Fucking error';
}
} else { $this->errors[] = 'Something wrong'; }
Просто из-за вложенности нужный нам код оказывается гдето в дали, что может хуево сказаться на непросредственной практичности - место на экране по сторонам не резиновое.
В упор не вижу, где ифы тебе помогают расширять благословенные 80 символов.
Посоветуйте годноты по HTML/CSS, JS, jQuery
Гайдец мануал. как начать что учить.
А там мб и в создание сайтов можно перекатиться в будещем
<td class="firstStr">
<?php
echo "<a href=\"http://students/list/{$page}/name\">Имя</a>";
?>
</td>
Ссылка для сортировки по имени выглядит вот так. Контроллер получает текующую страницу $page и тип сортировки "name", по нажатию сортируется, но как сортирнуть в обратную сторону по нажатию на эту же кнопку? Без жс.
>Без жс
Попробуй формировать ссылку сразу с параметром направления сортировки ?order=ascending, а в контроллере переключать этот параметр.
Запросы потом лень разбирать поэтому это будет выглядить так site/list/1/name/asc or desc. И так для каждого столбца...так и сделаю.
Ну пхп это отдельный язык? Или "надстройка" над хтмл? Зачем он нужен, что на нем делают? Чтоиттлитего изучать если я ноль, или начать с хтл?
Т.е на не важно какие записи были выбраны для 1 страницы, при попытке отсортировать выдаёт первые 10 строк из БД по типу сортировке. Лимит срабатывает, но только в виде ограничения выданных строк(10).
Там после 60 до 100 страницы ничЁ не понятно, сложнА.
Но потом вроде бы лучше становится, сейчас читаю про сами конкретные шаблоны - всё более-менее пока.
Читай оп пост.
Тебе слово OFFSET о чем-нибудь говорит?
в смысле, читаешь? Как художественную литературу? Как определяешь, что что-то понял?
Когда знаешь, допустим, про массивы, уже с ними повозился нормально, то если будешь читать, то ведь не будет нужды запускать этот код, всё ведь и так тебе понятно?
Вот так и тут.
После "Вектора" (до антикризисных мер, правда) там всё понятно в общем и целом. У Зандстры вот эти instanceof, ещё куча чего-то специфического очень долго объясняется перед шаблонами, я вот эту муть имел в виду.
Сделай сам вот на этой основе: https://www.w3schools.com/jquerymobile/tryit.asp?filename=tryjqmob_collapsible
Ну и вот тут посмотри разное: https://www.w3schools.com/jquerymobile/jquerymobile_collapsibles.asp
Идея такая, что даже если js отключен, то прилжение всё равно будет работать. Наверно, это не совсем js, но всё-таки мы всё равно обрщаемся к php через ajax.
Как остановить setInterval, который был вызван в предыдущем событии? Вообще я правильно ли делаю динамическую подгрузку? С этой функцией очень много проблем, например, она меняет контекст this на вызываемой функции и его нельзя поменять с помощью call.
$('.contact').on('click', function() {
...
setInterval(controller.refreshMessages, 500, ...); //Выводит сообщения и из предыдущего диалога.
});
Что нужно отправлять в ответ на успешный POST запрос? https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L193 Наверно помимо этого, я должен там ещё обновить сообщения.
Я правильно деалю то что вызываю события вне контроллера? https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L136-L198
Ничего то что я называю методы отображения одним словом, например, $view->index()? Я имею ввиду, мы же всё равно пишем $view, писать $view->viewIndex() похоже на тавтологию.
Как организовать конференции? Это же не совсем пользователи, к которым можно отправить сообщения, хоть и можно их так представить. Я имею ввиду, как проще было бы получать все контакты пользователя и его конференции один запросом, чтобы было удобно было сортировать или искать в базе данных? Или лучше отдельно получать контакты и отдельно получать конфернеции, при условии, что оптимизация нагрзуки на бд не имеет значения?
Я правильно вывожу новые элементы? Есть ли способ лучше? https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L115-L127
Как сделать уведомление о том что пользватель набирает сообщение? Нужно обнавлять какую-нибудь запись в БД об этом? Наверно, для нужно сделать отдельную таблицу conversations. Вместе с этим, отпадает вопрос как лучше организовать конференции.
Как лучше сохранять не отправленные сообщения? Сохранять их в куках или в бд, или же это тоже можно как-то реализовать с помощтю js?
Идея такая, что даже если js отключен, то прилжение всё равно будет работать. Наверно, это не совсем js, но всё-таки мы всё равно обрщаемся к php через ajax.
Как остановить setInterval, который был вызван в предыдущем событии? Вообще я правильно ли делаю динамическую подгрузку? С этой функцией очень много проблем, например, она меняет контекст this на вызываемой функции и его нельзя поменять с помощью call.
$('.contact').on('click', function() {
...
setInterval(controller.refreshMessages, 500, ...); //Выводит сообщения и из предыдущего диалога.
});
Что нужно отправлять в ответ на успешный POST запрос? https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L193 Наверно помимо этого, я должен там ещё обновить сообщения.
Я правильно деалю то что вызываю события вне контроллера? https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L136-L198
Ничего то что я называю методы отображения одним словом, например, $view->index()? Я имею ввиду, мы же всё равно пишем $view, писать $view->viewIndex() похоже на тавтологию.
Как организовать конференции? Это же не совсем пользователи, к которым можно отправить сообщения, хоть и можно их так представить. Я имею ввиду, как проще было бы получать все контакты пользователя и его конференции один запросом, чтобы было удобно было сортировать или искать в базе данных? Или лучше отдельно получать контакты и отдельно получать конфернеции, при условии, что оптимизация нагрзуки на бд не имеет значения?
Я правильно вывожу новые элементы? Есть ли способ лучше? https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L115-L127
Как сделать уведомление о том что пользватель набирает сообщение? Нужно обнавлять какую-нибудь запись в БД об этом? Наверно, для нужно сделать отдельную таблицу conversations. Вместе с этим, отпадает вопрос как лучше организовать конференции.
Как лучше сохранять не отправленные сообщения? Сохранять их в куках или в бд, или же это тоже можно как-то реализовать с помощтю js?
Нафейхуа в файлообменнике жквери? Ну если только для реализации перетаксивания мышкой файла в окно браузера.
>афаризмы
исправь, ебана
Где?
Такая себе идея делать чат через обычные пхп-скрипты и автообновление аяксом. Я бы лучше вебсокеты взял, они надежнее и проще в реализации таких вещей. Ну и для вывода сообщений можно было бы использовать какой-нибудь шаблонизатор, погугли, их достаточно много.
>В данном руководстве мы предполагаем, что ваш сервер имеет поддержку PHP и что все файлы, заканчивающиеся на .php, обрабатываются PHP.
Откуда у ньюфага сервер?
Делаю сейчас как раз в заказе чаты на vue. Использую сокет.ио, пхп для апи (почти все сделал закрытым). Функционал похож на вк, местами чуть больше, местами чуть меньше. Я ебнусь короче. В чатах столько мелочей ебучих, ппц просто. Хотя уже немного осталось.
Сокеты маст хев конечно, но вот стабильности там кот наплакал, хорошо что я взял свою готовую архитектуру с других проектов, а то это только на еблю с неочевидными особенносятми сокетов пару недель ушла бы.
>вебсокеты
Зачем я стал это гуглить
Зашел сюда http://petukhovsky.com/simple-web-socket-on-php-from-very-start/ а там наткнулся на пик
Жаль его. В 16 он "умнее" 99% остальных сверстников, просто потому что дрочит на какую-то левую хуету, на которую в его возрасте всем тупо насрать. А в 25 он уже спившийся неудачник, просто потому что маня-мир это одно, а реальность - другое.
Прикольно кстати то, что я годам к 20 перестал себя считать умнее среднего гражданина прямо, а если оно и так - мне наплевать. Чего и вам желаю, будущие программисты. Я свой ум только по работе использую, чего он мне еще дает - хз. Скорее мешает, много рефлексирую.
Ну это у многих так происходит. Сначала ты в 16 идеалист-максималист, и вокруг как будто тупое быдло, а к 20-25, понимаешь, что всё не однозначно в этом мире, и скорее сложно, и поэтому всем скорее похуй, ну и тебе уже тоже.
К 25 понимаешь что жалко нас всех и все одинакового страдают, просто кто-то лучше это скрывает
Почему у меня массив пустой? Я же регулярное выражение верно написал. Дальше оно должно было проверить и верные номера засунуть в массив.
Я про порядок решения задач. Я сделал часть задач на JS, остались на JQuery. Вот и думаю, решать их или переходить к файлообменнику.
Какой хитрый ход! Заменить массив на строку! Тебе нужно тщательней изучить как работает итерация массива. Задачки на массивы пропустил? Вот https://secure.php.net/manual/ru/control-structures.foreach.php хотя бы посмотри как работает первый пример.
Регулярное выражение очень далеко от верного.
Дальше, ты не засовываешь верные номера в массив, а выводишь совпадения найденные в строке. То есть, если написать preg_match("Hello World", '/^Hello (World)|(Cat)$/', $matches), то $matches будет равен array('Hello World', 'World').
https://secure.php.net/manual/ru/function.preg-match.php
>matches
>В случае, если указан дополнительный параметр matches, он будет заполнен результатами поиска. Элемент $matches[0] будет содержать часть строки, соответствующую вхождению всего шаблона, $matches[1] - часть строки, соответствующую первой подмаске, и так далее.
Очень плохо.
Тебе первым делом нужно итерировать массив $number, и, затем, на каждую итерацию выполнить проверку на твоё регулярное выражение.
Ты такой мерзкий и гнусный - это что-то.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<![endif]-->
</head>
Спасибо, но нет.
Каноничный.
Считай, что обьект это контейнер, в котором хранятся свойства и методы определенной тематики и назначения.
В общем, не хочу даже разбираться, что это за НЁХ, а хочу просто переписать этот код следующим образом:
Вместо <form method="POST"> и <input name="submit" type="submit" value="Зарегистрировать"> поставить просто кнопку, при нажатии которой срабатывает джава-скрипт и собирает данные из инпутов, а затем отправляет их аяксом в отдельный php-скрипт, в котором практически тот же самый код, что и в статье. Ну и потом он возвращает ответ успешно/не успешно. Так вот - как это выглядит с точки зрения фен-шуя? Я не слишком усложняю?
(У меня в одном php-файле, отвечающем за отрисовку страницы, есть два дива: на одном одна вкладка, а на втором другая. И две кнопки, которые меняют display:block; для них, чтобы юзер мог открывать их, как вкладки. На второй вкладке и стоит форма для регистрации первого пользователя, плюс список существующих, с кнопками удаления и смены пароля.)
C чего регулярное выражение далеко от верного? https://regex101.com/r/qF7vT8/3
Тут оно показало именно те, что нужно.
Правильное у меня выражение.
^\s?([+]\s[7]|8)\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W[0-9]\W*[0-9]$
https://regex101.com/r/qF7vT8/3
Сначала идёт пробел, а может и нет. Потом +7 или 8, потом 10 цифр, между которыми может идти любой символ, кроме цифры, подчёркивания и буквы.
1. \s - это не только пробел, но и табуляция, и переход на новую строку.
2. В первой скобке - зачем + и 7 в квадратные скобки взял? + просто экранируй, 7 - и в Африке 7.
3. [0-9] можно заменить на \d при желании.
4. А если бы 100 было цифр в номере, ты бы сто раз копипастил? Сделай нормально, а то нечитабельно же совершенно.
Потому что нужно немного написать и сразу проверять / тестировать
Опыт придёт с практикой.
В IDE когда будешь работать, то многие ошибки там будут подчёркиваться или иначе выделяться.
>>988855
Спасибо за понятный и доходчивый ответ по индексам. А можно ещё задачу, где нужно подумать над проставлением индексов? Ты вроде раньше кому-то предлагал БД для борды проектировать, но я, к сожалению, не смог этот пост найти c полным текстом задачи.
Недавно это делал, но на шарпе. В классический mvc это делается через методы, которые принимают на вход get-запрос. А в самом вью вместо статики передается вызов этого метода.
Формирование ссылки явно стоит вынести в отдельную функцию, а не писать прямо в шаблоне. Соответственно в эту функцию будут передаваться аргументами все значения, от которых зависит содержание ссылки:
- фраза для поиска
- название колонки
- выбранная колонка и направление сортировки
Ну а уже функция должна сравнивать текущую сортировку с названием колонки и выбирать нужное направление сортировки.
Если свойства никак не задействованы, зачем их делать? не нужно копировать то, что ты где-то увидел, нужно думать, зачем в коде та или иная строчка.
Твоя проблема в непонимании слова "модель". Там, где стоят свойства, модель предствавляет собой объект, который хранит информацию о какой-то сущности и у которого есть все описанные свойства. А TDG такой "моделью" не является, это объект для выполнения запросов к БД и ему конечно эти свойства не нужны. Но когда ты например запрашиваешь список студентов, тут как раз хорошо использовать модель для представления студента и возвращать список таких объектов-моделей.
Не путай "модель" (сущность) студента с компонентом "модель" из MVC. Это не одно и то же.
> Допустим в TDG я делаю отдельный класс для работы с базой,
Как-то странно написано. "в TGD"? Ты наверно имел в виду, "я сделал класс, который реализует паттерн TDG".
> а класс модели использую как хелпер в контексте этой модели,
Вот это не понял.
>А TDG такой "моделью" не является
Так я не называл её моделью, а в моём понимании модель это отдельный класс для свойств сущности. Вот я создал класс модели и задал свойства (1 пик), также в нем есть какие то методы которые относятся к ней. Второй класс для работы с бд (2 пик) , там я реализую функционал работы с бд и только его. Вопрос в том, как можно использовать свойства в модели (1 пик), и нужны ли они вообще?
Насчет борды, задача такая: есть борда, нужно сделать таблицы для хранения постов/тредов на ней и нужно сделать SQL запрос(ы) для постраничного вывода тредов, причем для каждого треда выводится ОП-пост и 3 последних поста. Треды отсортированы по дате последнего сообщения. Позже при желании можно прикрутить бамплимит (после X постов тред перестает подниматься) и сажу (посты которые не поднимают тред).
Также, если хочется задачу посложнее и пореалистичнее, в одном из старых тредов была задача про БД для сервиса вроде itunes: http://arhivach.org/thread/117571/#568993
А как у тебя первый класс Abiturient используется? Зачем он вообще нужен?
Обычно его используют для представления информации об абитуриенте. Например его можно передать в функцию сохранения абитуриента в БД, а функция поиска абитуриентов может возвращать результат в виде таких объектов.
У тебя же по сути в качестве модели класс TDG использует массив, а не объект.
И еще, вот у тебя есть строчка
$this->abiturientData = new Abiturient;
она очень странная. А зачем тебе внутри TDG хранить одну пустую модель абитуриента? Зачем TDG вообще что-то сохранять? Это же просто не нужно. Если ты хочешь вставить абитуриента в БД, ты его передашь как аргумент в функцию вставки.
Просто так. Это ни на что не влияет.
Вместо того, чтобы определять поиск и замену как 2 отдельных массива, лучше определить их как ключи и значения одного массива.
>>990968
Уточнения.
[+] это и есть примерно то же что \+
Если строго говорить, то \d это любая десятичная цифра из любого алфавита, а не только арабские цифры 0-9. Определение из мануала PCRE:
> \d any character that matches \p{Nd} (decimal digit)
Если вдруг любопытно, какие еще бывают цифры, то вот ссылочки:
- http://www.fileformat.info/info/unicode/category/Nd/list.htm
- https://en.wikipedia.org/wiki/Numerals_in_Unicode
>>990944
Копипасту надо убрать. Используй круглые скобки и квантификатор {N} для указания числа повторений.
Также, \W - это ведь любой символ, кроме букв, цифр и знака подчеркивания. То есть например знаки вопроса, звездочки итд. Слишком широко.
Просто так. Это ни на что не влияет.
Вместо того, чтобы определять поиск и замену как 2 отдельных массива, лучше определить их как ключи и значения одного массива.
>>990968
Уточнения.
[+] это и есть примерно то же что \+
Если строго говорить, то \d это любая десятичная цифра из любого алфавита, а не только арабские цифры 0-9. Определение из мануала PCRE:
> \d any character that matches \p{Nd} (decimal digit)
Если вдруг любопытно, какие еще бывают цифры, то вот ссылочки:
- http://www.fileformat.info/info/unicode/category/Nd/list.htm
- https://en.wikipedia.org/wiki/Numerals_in_Unicode
>>990944
Копипасту надо убрать. Используй круглые скобки и квантификатор {N} для указания числа повторений.
Также, \W - это ведь любой символ, кроме букв, цифр и знака подчеркивания. То есть например знаки вопроса, звездочки итд. Слишком широко.
else = "иначе, если ни одно из условий сверху не сработало, выполнить этот блок"
elseif (условие) = "иначе, если условия выше не сработали и если выполняется условие, выполнить этот блок"
То есть else всегда идет самым последним и в нем не указывается условие.
>>990911
Плохо, что ты не хочешь разобраться в проблеме, а убегаешь от нее. Лучше найди в чем была причина ошибки.
> Такое ощущение, что POST срабатывает при обновлении страницы
если страница загружена методом POST то конечно при обновлении он отправится повторно. Погугли про Post/Redirect/Get а еще лучше прочти мой урок про формы https://github.com/codedokode/pasta/blob/master/forms.md
> На второй вкладке и стоит форма для регистрации первого пользователя, плюс список существующих, с кнопками удаления и смены пароля.
А они защищены? Неавторизованный злоумышленник не сможет отправить такой запрос, который поменяет пароль другому пользователю или удалит его?
>У тебя же по сути в качестве модели класс TDG использует массив, а не объект.
Ну точно, можно в качестве аргумента и модель передать, я кажется понял все спасибо тебе.
А еще вопрос такой, вот в контроллере я могу кроме как обработки шаблона, делать методы нужные для конкретных шаблонов, то есть правильно ли так делать? Или же все нужно в отдельные классы хелперы выносить?
В уроке писал про статические методы: https://github.com/codedokode/pasta/blob/master/arch/di.md#Чем-плохи-классы-из-статических-методов
Главная проблема в том что отсутствует DI и в коде явно прописаны все зависимости и код получается спутанный.
>>990911
В статье есть много вещей которые копировать не стоит. Например не стоит использовать MyISAM, стоит ставить внешние ключи, не стоит использовать устаревшие функции вроде mysql_select_db.
>>990835
Это же отношения к вопросу вообще не имеет. Если бы ты открыл сайт https://github.com/aFarkas/html5shiv то прочел бы
> This script is the defacto way to enable use of HTML5 sectioning elements in legacy Internet Explorer.
Ты бы изучил что делает библиотека, прежде чем ее использовать.
>>990814
Проверяй:
- правильно ли использованы теги, вот например инфа: https://developer.mozilla.org/ru/docs/Web/HTML/Element/video
- верная ли ссылка на файл, то есть что загружается если составить абсолютную ссылку на файл и попытаться открыть
- в чем вообще проблема: ссылка неверная, файл не загружается, или загружается но не воспроизводится из-за неподдерживаемого формата
- в каком формате закодирован файл (не какое расширение)
- поддерживает ли моб. браузер такой формат видео ( https://developer.mozilla.org/ru/docs/Web/HTML/Поддерживаемые_медиа_форматы )
- попробуй открыть страницу не в WebVIew, а в встроенном браузере андроида и в других браузерах, если они есть
В уроке писал про статические методы: https://github.com/codedokode/pasta/blob/master/arch/di.md#Чем-плохи-классы-из-статических-методов
Главная проблема в том что отсутствует DI и в коде явно прописаны все зависимости и код получается спутанный.
>>990911
В статье есть много вещей которые копировать не стоит. Например не стоит использовать MyISAM, стоит ставить внешние ключи, не стоит использовать устаревшие функции вроде mysql_select_db.
>>990835
Это же отношения к вопросу вообще не имеет. Если бы ты открыл сайт https://github.com/aFarkas/html5shiv то прочел бы
> This script is the defacto way to enable use of HTML5 sectioning elements in legacy Internet Explorer.
Ты бы изучил что делает библиотека, прежде чем ее использовать.
>>990814
Проверяй:
- правильно ли использованы теги, вот например инфа: https://developer.mozilla.org/ru/docs/Web/HTML/Element/video
- верная ли ссылка на файл, то есть что загружается если составить абсолютную ссылку на файл и попытаться открыть
- в чем вообще проблема: ссылка неверная, файл не загружается, или загружается но не воспроизводится из-за неподдерживаемого формата
- в каком формате закодирован файл (не какое расширение)
- поддерживает ли моб. браузер такой формат видео ( https://developer.mozilla.org/ru/docs/Web/HTML/Поддерживаемые_медиа_форматы )
- попробуй открыть страницу не в WebVIew, а в встроенном браузере андроида и в других браузерах, если они есть
Будь внимательнее. У тебя много ошибок:
- в регулярке нет разделителя в конце и нет флага u (хотя он тут ни на что не влияет, но все же)
- внизу выводятся ошибки
- переменной $number не существует, а ты ее пытаешься использовать
-preg_match работает только с одним номером за раз, а не принимает на вход массив номеров
Конечно ты делаешь неправильно. Во-первых, единственные публичные методы у контроллера - это обычно методы вида "вывести страницу такую-то/обработать запрос".
Метод форматирования даты лучше всего сделать статическим в отдельном классе-хелпере реализующем паттерн Utility Class (класс с статическими методами).
Непонятно зачем в контроллере свойство date. Это свойство контроллера?
Неправильно выбрано название datamodel. Оно должно называться abiturientGateway.
Неправильно что ты используешь одну переменную $date для хранения строки и объекта.
Неправильно называть переменную dataArr так как это название ничего не значит: любая переменная хранит данные.
Не надо сокращать errors как err.
В помощь: https://github.com/codedokode/pasta/blob/master/good-code.md
>Непонятно зачем в контроллере свойство date. Это свойство контроллера?
Да, это свойство выводит текущую дату, и её наверно тоже в отдельный класс насколько я понимаю
Что ты пытаешься сделать во втором цикле?
Во-первых count() считает сколько элементов в массиве. В php строка это строка, а не массив символов.
Во-вторых, в цикле for ты сравниваешь переменную $i с 0, а не присваиваешь его ей. Оператор ==, это сравнение а не присваивание. Почему ты решил что должно быть сравнение?
Затем ты сравниваешь $i <= $len, и цикл обойдет $len + 1 раз, потому что ты начинаешь с 0. Цикл будет выполняться пока значение второго аргумента истинно, то есть в твоем случае $i <= $len, цикл будет выполняться от 0 до и включая $len. Вот пример https://3v4l.org/EPLQc посчитай сколько раз выполнился цикл. Если ты хочешь чтобы цикл обходил ровно $len раз, то тебе нужно либо начинать цикл с 1, либо выполнять этот цикл пока $i меньше $len $i < $len.
Я тебе уже говорил, что ты делаешь из $CorrNumb не массив правильных номер а массив совпадений. Если ты хочешь получить массив правильных номеров, то лучше сначала создать еще массив $matches и затем поместить его в preg_match обычно так и делают. И далее уже добавлять в $CorrNumb >строку, соответствующую вхождению всего шаблона
if (preg_match($regexp, $number, $matches)) {
//добавляем строку в $CorrNumb
}
Перечитай как работает функция preg_match.
Для чего нужна переменная $regexpRepl?
Ты нарочно делаешь такое форматирование кода? Перечитай второй поста треда.
>- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
По-прежнему, очень много ошибок.
> в отдельном классе-хелпере реализующем паттерн Utility Class (класс с статическими методами).
Зачём всё подряд из Java тянуть? В PHP ведь можно поместить функции в неймспейс, а Composer подгрузит (правда, не без пинка). Нет ничего плохого в чистых функциях: https://nikic.github.io/2012/08/10/Are-PHP-developers-functophobic.html
Всякие Utils лишь утяжеляют код ненужными приставками, когда можно написать use function namespace\foo;
>Если строго говорить, то \d это любая десятичная цифра из любого алфавита, а не только арабские цифры 0-9
Ты чо дохуя умный штоле еба?777 Ща как уебу нахуй спасибо, не знал
>не стоит использовать MyISAM
Воу-воу-воу! Можно, пожалуйста, поподробнее, почему? Я для своего проекта выбрал ее, потому что пишут что она быстрее при определенных условиях (которые у меня соблюдаются), транзакции мне тут не нужны. Какие подводные?
Пиздит он тебе.
Он даун просто. Форыч норм, единственное чем он сбивает, что работает с копией массива, а если хочешь менять значения перебираемого массива inplace - то нужно явно передавать значения по ссылке. Но вообще лучше так не делать вовсе.
https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Controllers/RandomController.php#L21-L38
https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Models/QuotesModel.php#L83-L151
А разгадка то одна, нет опыта - все делается по необходимости.
Поломалась таблица MyISAM когда вставлял данные и отключили свет. Я так понимаю, с InnoDb такого бы не произошло?
Проблема в том, что сохранить текущий тип сортировки можно только в сессию, ведь при вызове новой страницы - программа выполняется с нуля. ->в адресную строку попадает адрес с типом сортировки->FrontController получает ссылку, разбивает, запускает нужный контроллер и переадаёт ему параметры...
Заскринь код и выложи картинкой, чо как маленький? Твоя версия хоть умещается на экране?
Не подгрузит. PSR-4 работает только с классами, функции использовать (и импортировать) неудобно. Да и я не вижу большой разницы между статическим методом и функцией. Удобнее сделать именно класс.
Дело тут не в боязни, а в том, что просто с функциями менее удобно работать. Да и они не вписываются нормально в неймспейсы. Ведь в PSR-4 неймспейс соответствует папке, и непонятно, как хранить функции? Каждую в своем файле? В одном файле? Удобнее все же сгруппировать их в класс, а ностальгирующие по Го, Питонам и Руби могут отправиться писать на этих языках.
Кстати в Го примерно та же проблема: там модуль соответствует папке, и просто непонятно как раскладывать функции по файлам в этой папке. Ужасно сделано.
Нагугли сравнение MyISAM и InnoDB. Во-первых, InnoDB умеет блокировать отдельные строки, а не всю таблицу при записи (то есть параллельные операции записи в MyISAM будут выполняться последовательно, что медленнее), не поддерживает транзакции, внешние ключи. Это просто более старый движок.
Насчет производительсности в каких-то редких случаях - предложил бы померять, скорее всего разница там незначительная и никак не оправдывает отсутствия внешних ключей и транзакций.
>>991409
С какой-то версии он стал доступен и в InnoDB.
>>991431
php7 тут не при чем. Работа с копией массива это правильная вещь, так как это значит, что цикл работает предсказуемо даже если по ходу выполнения менять массив. Иначе как ты поймешь, как этот цикл будет работать, если сам массив меняется по ходу выполнения?
>>991459
Если страница не найдена, то надо отдавать ошибку 404. Это поможет во многих случаях, а то, что ты делаешь, например запутает поискового бота и твой сайт получит низкий рейтинг в поисковых системах. Также, бот, который проверяет целостность ссылок не сможет обнаруживать битые ссылки. То есть так делать не надо.
Получение соседних id я бы советовал сделать отдельным методом.
В контроллере у тебя встречаются длинные выражения вроде
$this->data['quote']
$this->request->getProperty('quote_id')
Не надо их копипастить, удобнее сделать переменную и использовать ее.
if в контьроллере лучше перевернуть, чтобы в начале шла более короткая ветка. Если в конце ее поставить return , то else будет не нужен.
Нагугли сравнение MyISAM и InnoDB. Во-первых, InnoDB умеет блокировать отдельные строки, а не всю таблицу при записи (то есть параллельные операции записи в MyISAM будут выполняться последовательно, что медленнее), не поддерживает транзакции, внешние ключи. Это просто более старый движок.
Насчет производительсности в каких-то редких случаях - предложил бы померять, скорее всего разница там незначительная и никак не оправдывает отсутствия внешних ключей и транзакций.
>>991409
С какой-то версии он стал доступен и в InnoDB.
>>991431
php7 тут не при чем. Работа с копией массива это правильная вещь, так как это значит, что цикл работает предсказуемо даже если по ходу выполнения менять массив. Иначе как ты поймешь, как этот цикл будет работать, если сам массив меняется по ходу выполнения?
>>991459
Если страница не найдена, то надо отдавать ошибку 404. Это поможет во многих случаях, а то, что ты делаешь, например запутает поискового бота и твой сайт получит низкий рейтинг в поисковых системах. Также, бот, который проверяет целостность ссылок не сможет обнаруживать битые ссылки. То есть так делать не надо.
Получение соседних id я бы советовал сделать отдельным методом.
В контроллере у тебя встречаются длинные выражения вроде
$this->data['quote']
$this->request->getProperty('quote_id')
Не надо их копипастить, удобнее сделать переменную и использовать ее.
if в контьроллере лучше перевернуть, чтобы в начале шла более короткая ветка. Если в конце ее поставить return , то else будет не нужен.
Увы, не знаю. По идее в InnoDB есть логи, так что в теории не должна поломаться (но может стоит проверить на практике).
Тут написано что проблема повреждения таблиц в MyISAM есть: https://www.percona.com/blog/2006/07/30/mysql-crash-recovery/
Вообще, про сравнение MyISAM и InnoDB много копий сломано, например:
http://blog.danyll.com/myisam-vs-innodb/
http://stackoverflow.com/questions/20148/myisam-versus-innodb
https://www.percona.com/blog/2009/01/12/should-you-move-from-myisam-to-innodb/
Я всегда стараюсь использовать InnoDB.
>>991482
Текущий тип сортировки может быть указан в query string-параметрах:
/index.php?sort=-name&page=2&query=Ivan
Ты мыслишь не в парадигме REST. REST говорит о том, что параметры отображения страницы указываются в URL, а не спрятаны в каких-то сессиях, куках и тд.
То есть в REST мы сортировку указываем в URL.
Если сортировку хранить в сессии это только вызовет проблемы, так как куки и сессия общие для нескольких вкладок браузера и они будут влиять друг на друга.
Соответственно сессия тут не нужна. Определяешь тип сортировки в контроллере и передаешь переменную в шаблон.
>>991493
Такие сложные вычисления не надо делать в шаблоне. Шаблон для отображения данных.
Также, функции в твиге есть, и их можно туда добавлять. Но не для таких целей.
Увы, не знаю. По идее в InnoDB есть логи, так что в теории не должна поломаться (но может стоит проверить на практике).
Тут написано что проблема повреждения таблиц в MyISAM есть: https://www.percona.com/blog/2006/07/30/mysql-crash-recovery/
Вообще, про сравнение MyISAM и InnoDB много копий сломано, например:
http://blog.danyll.com/myisam-vs-innodb/
http://stackoverflow.com/questions/20148/myisam-versus-innodb
https://www.percona.com/blog/2009/01/12/should-you-move-from-myisam-to-innodb/
Я всегда стараюсь использовать InnoDB.
>>991482
Текущий тип сортировки может быть указан в query string-параметрах:
/index.php?sort=-name&page=2&query=Ivan
Ты мыслишь не в парадигме REST. REST говорит о том, что параметры отображения страницы указываются в URL, а не спрятаны в каких-то сессиях, куках и тд.
То есть в REST мы сортировку указываем в URL.
Если сортировку хранить в сессии это только вызовет проблемы, так как куки и сессия общие для нескольких вкладок браузера и они будут влиять друг на друга.
Соответственно сессия тут не нужна. Определяешь тип сортировки в контроллере и передаешь переменную в шаблон.
>>991493
Такие сложные вычисления не надо делать в шаблоне. Шаблон для отображения данных.
Также, функции в твиге есть, и их можно туда добавлять. Но не для таких целей.
Вместо $this->dbh->query лучше сделать методы queryAssoc, querySingleValue, querySingleRow, queryColumn и тд. Посмотри, как сделано в Doctrine DBAL (англ):
http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#fetchall
Это какой-то баг, попробйу почистиь кеш браузера и зайти снова. Ну или использовать другой сайт, они ищутся по словам "run php code online".
Ну все интереснее, чем в миллионный раз обсуждать, как кто-то циклы или массивы понять не может
КАК ОПРЕДЕЛИТЬ ТИП СОРТИРОВКИ? СКАЖИ ПРЯМО, хватит повторять - "засуть тип сортировки в адресную строку", параметры всегда там! Все там! Но нажатием на ОДНУ и ту же ссылку НЕВОЗМОЖНО передать разные параметры.
Можешь прямо сейчас начинать. 90% фриланса это абсолютно недееспособные дцпшники, ты никого не удивишь этим.
Я не хочу фрилансить постоянно. Просто чтобы узнать как работать с людьми заказчиком, заставлять себя укладываться в сроки и тд
Нужно генерировать разные ссылки в зависимости от текущей сортировки. То есть если у нас включена сортировка +name, то ссылка на колонке должна содержать -name.
>>991688
Для начала, как попробуй зайти на сайт фриланса и изучить имеющиеся там задания. Там есть категории, изучи их. Там есть faq и помощь. Изучив, можешь уже задавать вопросы.
>Нужно генерировать разные ссылки в зависимости от текущей сортировки.
Как запоминать текущую сортировку?
>То есть если у нас включена сортировка +name, то ссылка на колонке должна содержать -name.
Что? Нажимаю на name - контроллер получает параметры /name/asc
Нажимаю снова на name - контроллер получает все те же параметры /name/asc КАК запомнить и переключить ASC в DESC?
Ты совсем необучаемый, тебе уже разжевали ответ донельзя. Генерируешь ссылку /name/asc, кликаешь по ней, контроллер получает /name/asc. При выводе шаблона меняешь asc на desc и получаешь ссылку /name/desc. Тыкаешь опять по этой ссылке - в контроллер уже прилетает desc.
можно еще в виде выпадающего списка сделать, но тогда все равно надо будет писать функцию, чтобы текущий тип сортировки был выбран
Сразу вспомнился FrontPage с тоннами генерируемого дерьма на кубический сантиметр полезного кода.
О главном: ты не сможешь отредактировать его, если не разбираешься.
если (в URL стоит ?sort=name/asc) {
выводим ссылку ?sort=name/desc
} иначе {
выводим ссылку ?sort=name/asc
}
>Именно объекты а не статические свойства и методы, ведь в большинстве задач используется не больше одного экземпляра класса, зачем тогда нужны все эти копии? Какой смысл?
А ты можешь, например, изменять состояние статических свойств?
http://ideone.com/W1iHIy
Что я сделал не так и как можно сделать лучше?
Нужен совет.
Хочу написать сайт-энциклопедию. Грубо говоря у каждой статьи в ней должна быть своя категория, группа, дата и многое другое. После чего хочу организовать по всей энциклопедии удобную группировку по датам и т.д.
Изучил HTML, CSS и так понимаю, дальше надо копать в сторону MySQL, PHP(Ведь нужен, да?) и что еще?
В общем, что нужно еще для сайта-энциклопедии?
Почему же?
Ты описал википедию
Прост)))
Сегодня запилил редактирование. Пожалуй 2/3 уже сделал. Правда, дохуя чего переделать надо из уже сделанного.
nano /etc/apt/sources.list
deb http://ftp.debian.org/debian/ stretch-updates main contrib non-free
deb-src http://ftp.debian.org/debian/ stretch-updates main contrib non-free
deb http://security.debian.org/ stretch/updates main contrib non-free
deb-src http://security.debian.org/ stretch/updates main contrib non-free
В другой раз спрашивай в линукс-треде, питух. Больше тебе помогать не буду.
>>992092
Вот не надо такие советы давать, и не надо им следовать так как вполне может сломаться система. Надо давать объяснения, а не умничать тут.
php7 есть не во всех версиях дебиан. Для начала, ознакомься, какие версии вообще существуют: https://wiki.debian.org/ru/DebianReleases
Ты скорее всего сидишь на stable версии - а туда включают только пакеты, которые какое-то время оттестированы и в которых большинство багов выявлено и исправлено. php7 пока не считается "стабильным" разработчиками debian.
Соответственно, выхода 2:
- апгрейдиться на более новую версию дебиана, testing или даже unstable (если это виртуальная машина то в принципе тебе терять особо нечего)
- подключить сторонний репозиторий вроде dotdeb, который содержит нужную версию php: https://www.dotdeb.org/
Помни, что подключая сторонний репозиторий ты добавляешь его цифровую подпись и автоматически начинаешь доверять его авторам. Они могут при установке php или любого другого пакета одновременно заменить любые программы и библиотеки в твоей системе, например, установить бекдор, если захотят, и выполнить любой код от имени root (по умолчанию бекдор могут установить только разработчики дебиан).
Почему-то про это никто не пишет. Кругом только люди, которые бездумно копируют инструкции, не понимая, что они делают.
В первом случае для наглядности, наверное.
А в остальных, чтобы не рвать строку типа:
"блаблабла это", $значениеблаблабла, "продолжение текста"
То есть это совсем не обязательно? В таких местах я сам могу ставить скобки для удобности?
Получается так
Почему Symfony и Zend считается ынтырплайз фреймворкaми, а остальные нет?
Да я упорот был когда спрашивал, после 12 часовой смены идти учить пхп вообще плохая идея. Щас сел бодрый, за 15 минут решил проблему с сортировкой.
Класс не будет называться студент,
это ошибка. Условия не прозрачные и запутанные, i know. Условия здесь для нормального отображения когда сортировка пользователем не задана, а то начинают в строку запроса попадать лишние слэши, да типы сортировок по умолчанию.
Первый случай - для наглядности. В целом по приоритету операций умножение и так будет первым. Однако я сам всегда руками скобки ставлю от греха подальше, и для лучшей наглядности, притом на любых языках.
Второе опять же для удобства, можно и без этого, но лучше не надо, не будь говном.
Но почему тогда во втором случае стоят фигурные скобки? Можно так же ставить обычные?
Функция должна возвращать ссылку, а не выводить. И нежелательно формировать HTML код в функции, а не в шаблоне. И htmlspecialchars не забывай.
во вотором случае имя переменной подставляется. КОгда строчка будет выводиться, будет не имя апеременной, а ее значение.
Это значит твой код выполняется дольше 3-5 секунд что довольно много. Может там вечный цикл? Попробуй уменьшать код и опытным путем найти тормозящее место.
Также можно мерять время выполнения через microtime(true).
Чтобы снять ограничение, надо установить на компьютер PHP и запускать код у себя, инструкции в ОП посте.
Cпасибо большое! Я думал сойду с ума уже, но не решу задачу с айфоном в кредит. Час все проверял, а оказалось, что всего лишь лишняя фигурная скобка поставлено и сайт как на зло не говорил об этом. Но и php на комп поставлю. Все равно потом придется
Браузеры иногда отображают адресную строку в декодированном виде. Также они иногда декодируют punycode в доменах. Попробуй кликнуть в адресную строку или скопировать УРЛ - может он выведется как есть.
Также, содержимое Location можно увидеть в отладчике на вкладке Network.
Годный ответ, действительно в отладчике увидел, что ссылка закодирована, в итоге ошибка оказался не в том, что строка не кодируется, а совершенно в другом. thx.
Ты задачу-то покажи - инфа 99%, что там не всё идеально, поскольку можно улучшить. Либо вообще неправильно работает, хотя ОП вроде указал всё сейчас в учебнике для ориентира.
<meta name='data' content='<?php echo META_JSON_DATA; ?>'>
?
Че молчите то. Бамп
тем, что я тебе в челюсть двину... Хотя бы санацию через htmlspecialchars делай, мало ли что там
В общем, есть один абстрактный класс. Назовём его Animal. У абстрактного класса есть некий порождающий этот же класс метод. Допустим, что там просто
return clone $this;
Как мне в PHPDoc-блоке отметить, что этот метод возвращает не просто Animal, а для
class Cat extends Animal {}
этот метод возвращает Cat, ну и для собаки соответственно Dog?
Док вида
@return static
@return self
@return $this
Идеей не кушаются.
___________________-
Аналогично как мне задать в phpdoc-блоке некое виртуальное свойство, допустим $__clone_shit, которое тоже возвращает именно конечного потомка (static::class), а не Animal.
Это нужно только для того, чтобы я нормально видел ссылки на используемые поля и чтобы мне Идея сразу подсвечивала методы/поля наследников, и мне не приходилось через phpdoc писать
@var Cat $cat
Само собой я знаю, что есть метод лоб и можно просто писать у каждого наследника свой phpdoc-блок и переопределять функцию, которая просто будет делать return::parent(... но можно ли это сделать автоматически, без извращений?
Код стрёмный. По первому скрину:
Выносить действия конструктора в отдельный метод init смысла нет, код от этого не становится легче (на Yii не смотри, у них много сомнительных практик используется). Ну и ответь на вопрос, чем вообще характеризуется "Запрос"? Как минимум типом (GET, POST и т.д) и путём (/user/1). Без этих вещей запрос существовать не может, поэтому логично потребовать их в конструкторе.
Класс Request у тебя неудобный, я не могу из консоли создать объект вот так:
$request = new Request('/path', 'GET');
Такие реквесты удобно использовать в юнит-тестах, чтобы "эмулировать" запрос программно, а не руками вводить в браузере.
В Symfony ещё используется статический конструктор:
$request = Request::createFromGlobals(); // Создаёт объект на основе глобальных переменных.
Это вообще я основы ООП рассказываю.
По второму скрину:
Почему заголовки проставляются в обход класса Response? Или у тебя Request есть, а Response нет? Ну и название класса Errors неоднозначное, я вот подумал, что это класс, представляющий список ошибок, например валидации.
По третьему:
- PDO незачем в кишки прятать, что если я захочу в конфигурации БД указать PostgreSQL, а не MySQL? Мне нужно лезть в твой код и править, а такие вещи должны настраиваться вне класса, в конфиге. Если захочу использовать SQLite, то там вообще юзера и пароля не будет. Используй DI.
- ConfigModel читается как "модель конфига", странное название. И зачем синглтон для конфига?
Основные проблемы c ООП, DI, MVC. Обо всём этом написано у ОПа хорошо, особенно про DI.
>Это вообще я основы ООП рассказываю.
Интересно, почему программисты такие токсичные. Ведь, наверняка, искренне уверен, что не пытается быть тщеславным и унизить другого. А получается именно это.
Синглтоны, внедрение зависимостей и статические конструкции, это не основы. Основы, это наследование Котов и Собак от класса Животные.
Я спросил одно, а в ответ весь код стали критиковать, хотя я этого не спрашивал и мне выше тоже самое уже написали, я просто не успеваю все читать и переделывать. Смешно, что бессмысленными называются конкретные примеры из Зандстра.
Просто бомбит. Собственно, отвечать на этот пост не надо, я лишь получу еще один ушат говна в мой адрес в абсолютно таком же стиле. Это просто черта характера с которой ничего не поделать.
Еще вспомнил, что когда я откровенное говно полгода назад постил, где ни классов, ни архитектуры ни намеков на ООП, даже коннект к БД через mysql(), то желающих обосрать не было.
>Помни, что подключая сторонний репозиторий ты добавляешь его цифровую подпись и автоматически начинаешь доверять его авторам. Они могут при установке php или любого другого пакета одновременно заменить любые программы и библиотеки в твоей системе, например, установить бекдор, если захотят, и выполнить любой код от имени root (по умолчанию бекдор могут установить только разработчики дебиан).
Это важно иметь ввиду, что сторонние репозитории могут установить бекдор, но почему вы посоветовали dotdeb.org в качестве доверенного, а не зеркала debian.org, с которого скачивают сам дистрибутив?
Анон, а ты можешь переписать код в таком стиле, чтобы не использовать функции? ПАМАХИ, УМОЛЯЮ.
http://ideone.com/KwvN5W
ОП-пост мы не читаем, да?
В опенсурс проекте на гитхабе юзается. Я немного не понимаю нахуя, но то что видно какой-то key в исходнике страницы -- меня пугает. Объясни что за мета джсон данные и как они важны?
Я уже неделю учу по шапке php и зарабатываю 300к/сек. Планирую через неделю до наносекунды добраться
Блииииин, хочухочухочу! Отлично, если обычный человек зарабывает 300к/сек, то такой гений как я сможет заработать все деньги этого мира! Вкатываюсь через 5 минут, ждите!
даларов ?
dotdeb это сторонний репозиторий, который не является заркалом debian.org. В нем выложены пакеты, которых в дебиане нет (иначе зачем он был бы нужен).
Дело кстати не только в бекдорах (dotdeb вроде известный), но еще и в том, что что-то могут случайно сломать, например, они могут обновить какую-то библиотеку, которая используется и другими программами, и нечаянно что-то сломать. Так как это сторонний репозиторий и никто в дебиане не тестирует свои пакеты на совместимость с ним.
Я сам им впрочем пользовался и вроде ничего не сломалось. Но важно понимать, какой уровень доступа к системе ты даешь авторам репозитория.
>Плохо, что ты не хочешь разобраться в проблеме, а убегаешь от нее.
Уже четвёртый месяц пишу небольшую систему и хочется её, наконец, выпустить, хоть тушкой, хоть чучелом. Плюс, у меня там вообще почти все вызовы пхп-кода так оформлены. Единообразие полезно.
>если страница загружена методом POST то конечно при обновлении он отправится повторно. Погугли про Post/Redirect/Get а еще лучше прочти мой урок про формы https://github.com/codedokode/pasta/blob/master/forms.md
Не, страница просто грузится. А урок прочитаю.
>А они защищены?
Сложный вопрос. С одной стороны, страница, с которой идут вызовы кода, который работает с бд, защищена. Но если рядом положить другой пхп-файл без защиты и вызвать с него, то действия будут произведены. Это дыра, но на неё я, опять же, плюнул ради ускорения релиза.>>991276
>mysql_select_db
Знаю. Потом заменю на PDO.
>не стоит использовать MyISAM, стоит ставить внешние ключи
Запишу в to do list, потом погуглю, что к чему.
Лолчто? Если под функциями ты имеешь в виду встроенные функции по работе с массивами (count, array_search, array_slice, implode), то НЕ могу, яж новичок. Чтоб вот так просто, как в твоем примере — нет. Это какая-то высшая магия. Сорре.
Установил Atom, установил расширение Remote-FTP. При открытии файла с ftp в кодировке win1251(CMS Bitrix): http://joxi.ru/RmzYLDgIWXZokr. Смена кодировок не дает результата.
Установил VS Code. Установил расширение FTP-Simple. Тоже самое. VS Code автоматически определяет кодировку как UTF-8. Повторное открытие файла в кодировке Windows-1251 ничего не исправляет.
ОС Windows 10 Pro
Atom был для сравнения установлен на Kubuntu 16.04 с расширением Remote-FTP. Кодировка применяется и все работает отлично. ЧЯДНТ?
Может файл не в Windows-1251? Если его скопировать и открыть с диска, та же проблема?
>>992615
Так как у нас учебный тред, то для нас самое важное - это научить людей писать правильно.
>>А они защищены?
> Сложный вопрос. С одной стороны, страница, с которой идут вызовы кода, который работает с бд, защищена. Но если рядом положить другой пхп-файл без защиты и вызвать с него, то действия будут произведены. Это дыра, но на неё я, опять же, плюнул ради ускорения релиза.
Мне кажется, тут кто-то кого-то не понял. Злоумышленник имеет возможность отправлять любые HTTP-запросы к сайту. Соответственно, проверки должны стоять в том скрипте, который выполняет действие.
Ну например, у тебя есть скрипт 1, который выводит форму с кнопкой удаления пользователя и есть скрипт 2, обрабатывающий POST запрос, который отправляется при нажатии кнопки и допустим скрипт 2 в ответ на этот запрос удаляет выбранного пользователя. Проверка должна стоять в скрипте 2, он должен проверять, что запрос отправлен администратором, а не злоумышленником без прав. А если отставить скрипт 2 без проверки, а защищать скрипт 1, то это лишь видимость защиты.
> Но если рядом положить другой пхп-файл без защиты и вызвать с него, то действия будут произведены.
Это не уязвимость так как такой файл злоумышленник загрузить не может.
>если страница загружена методом POST то конечно при обновлении он отправится повторно.
> Не, страница просто грузится.
Действия, которые меняют состояние сервера (удаление, изменение, добавление информации) должны делаться только через POST-запросы (то есть в форме должен стоять method="POST"). GET-запросы только для случаев, когда информация не меняется, то есть для получения информации с сервера.
Если тебе непонятны слова вроде POST-запрос, то может быть стоит почитать где-нибудь про основы протокола HTTP.
>е в Windows-1251? Если его скопировать и открыть с диска, та же проблема?
VS Code: с диска он открывается сначала в utf-8 затем принудительно указываю открыть в Win-1251
Atom: в обоих случаях открывает в UTF-8
Кодировка Win-1251, т.к. при установке CMS Битрbкс была указана она.
Два ПК проверил на Win10 - одинаковые ошибки.
Один ПК на Kubuntu - ошибок нет и кодировка пменяется.
Чтобы не обманули, можно использовать escrow-сервисы вроде тех, что есть на fl (безопасная сделка), но для маленьких сумм там наверно слишком много возни.
>>992591
Вряд ли, мало кто может за месяц изучить все нужное. Месяцев 6-8 уходит. Если твоя цель - зарабатывать 6000 р в месяц (меньше МРОТ?) то может тебе проще дворником устроиться и пару часов в день дворы подметать? Программисты за 100 долларов в месяц не работают.
>>992524
Какие у тебя странные пожелания.
По твоей задаче, тебе же вроде уже писали:
- сортируем годы по возрастанию или убыванию
- удаляем все что меньше (или больше заданного)
- берем первые (последние) N элементов
Другой вариант: сортируем годы, находим на какой позиции находится текущий, и вырезаем кусок массива вокруг этой позиции.
То есть это задача на работу с массивами. В нашем учебнике в ОП посте кстати есть глава про массивы.
>>992509
Может быть у ОПа не было времени, в таких случаях он комментирует только решения своих задач, а может он решил что новичку не очень нужна эта критика.
>>992504
Где токсичность-то? Запостил код в тред - получил комментарии. Там же код комментируют, а не твою личность. Это ты по моему как-то резко воспринимаешь критику своего кода.
Да и тем более может он первый раз твой пост увидел. Откуда он должен знать что тебе уже писали эти замечания?
Если тебе кажется что что-то пишут неправильно, так дай аргментированный ответ. Вспомнил Зандстру - так хоть главу или номер страницы напиши, чтобы можно было найти и сравнить.
А ты вместо этого начинаешь переходить на личности и обвиняешь людей в "токсичности".
Тебе ведь пишут, почему лучше так или иначе сделать, а не просто предлагают верить на слово.
А что касается твоего вопроса, то я уже писал, что тебе для начала надо определиться, что ты будешь называть "моделью" и только после этого можно сказать, правильно ты назвал класс или нет.
Чтобы не обманули, можно использовать escrow-сервисы вроде тех, что есть на fl (безопасная сделка), но для маленьких сумм там наверно слишком много возни.
>>992591
Вряд ли, мало кто может за месяц изучить все нужное. Месяцев 6-8 уходит. Если твоя цель - зарабатывать 6000 р в месяц (меньше МРОТ?) то может тебе проще дворником устроиться и пару часов в день дворы подметать? Программисты за 100 долларов в месяц не работают.
>>992524
Какие у тебя странные пожелания.
По твоей задаче, тебе же вроде уже писали:
- сортируем годы по возрастанию или убыванию
- удаляем все что меньше (или больше заданного)
- берем первые (последние) N элементов
Другой вариант: сортируем годы, находим на какой позиции находится текущий, и вырезаем кусок массива вокруг этой позиции.
То есть это задача на работу с массивами. В нашем учебнике в ОП посте кстати есть глава про массивы.
>>992509
Может быть у ОПа не было времени, в таких случаях он комментирует только решения своих задач, а может он решил что новичку не очень нужна эта критика.
>>992504
Где токсичность-то? Запостил код в тред - получил комментарии. Там же код комментируют, а не твою личность. Это ты по моему как-то резко воспринимаешь критику своего кода.
Да и тем более может он первый раз твой пост увидел. Откуда он должен знать что тебе уже писали эти замечания?
Если тебе кажется что что-то пишут неправильно, так дай аргментированный ответ. Вспомнил Зандстру - так хоть главу или номер страницы напиши, чтобы можно было найти и сравнить.
А ты вместо этого начинаешь переходить на личности и обвиняешь людей в "токсичности".
Тебе ведь пишут, почему лучше так или иначе сделать, а не просто предлагают верить на слово.
А что касается твоего вопроса, то я уже писал, что тебе для начала надо определиться, что ты будешь называть "моделью" и только после этого можно сказать, правильно ты назвал класс или нет.
Как компосер настроить? Что прописать?
Никак. Более того, если у тебя в методе написано @return Animal, и ты получаешь из этого метода объект, то ты не должен додумывать, что будет возвращен именно объект Cat и должен использовать только имеющиеся в Animal поля и методы.
@return Animal значит что будет возвращен объект Animal или любой его наследник, в том числе Wolf, который может еще даже не написан.
Можно в Cat и Dog впрочем переопределить этот метод и сделать, чтобы они возвращали не Animal, а конкретного его наследника.
При этом надо соблюдать принцип Лисков, что объект-наследник можно подставить в код вместо предка, и метод-наследник должен возвращать объект Animal или его наследника.
>Дан рост школьника и рост его одноклассников. Надо найти, сколько человек в классе выше, чем наш герой.
Однозначно.
Совсем все не так сделал.
Если коротко, алгоритм должен быть таким: в цикле идешь по одноклассникам, каждую итерацию сравниваешь рост анона с текущим одноклассникам, если он больше, то инкрементируешь счетчик, а после цикла выводишь счетчик свой.
> Аналогично как мне задать в phpdoc-блоке некое виртуальное свойство, допустим $__clone_shit, которое тоже возвращает именно конечного потомка (static::class), а не Animal.
Никак, и есть ощущение, что ты там что-то переусложняешь. Также, имена, начинающиеся с 2 подчеркиваний, зарезервированы для использования разработчиками PHP и ты не должен свои поля называть так.
Сами "виртальные" свойства, создаваемые через __get, можно описать с помощью @proeprty, но магических методов по возможности лучше избегать. Лучше сделать реальное свойство.
>>992590
Это константа, определенная где-то в коде проекта. Тебе стоит начать с изучения синтаксиса языка PHP.
>>992274
Хороший совет в общем-то, но тут бы он не помог.
>>992157
>>992123
Скобки ставят, чтобы писать более сложные выражения и чтобы отделить переменную от окружающего текста. Ставить круглые нельзя, именно фигурные надо. Можно без них в некоторых случаях, описано в мануале http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
>>992153
Я бы советовал не заморачиваться с вставкой сортировки в URL, а просто использовать аргументы ?sort=.... (то есть у нас есть одна страница списка студентов, и разные параметры ее отображения), а если ты вставляешь аргументы в URL - то обеспечить чтобы каждая страница была доступна ровно по одному URL. С точки зрения поисковиков в общем это плохо, что есть куча страниц с разными URL, но с одними и теми же данными, просто выводящимися в разном порядке (это однако можно исправить добавлением метатега canonical).
>>992134
А что такое "энтерпрайз"? Это большие, сложные проекты, которые обычно развивают годами, соответственно нужно чтобы фреймворк был пригоден для их написания.
Также, предполагается что в хорошем фреймворке есть какие-то готовые решения для часто встречающихся задач. Ну например, роутер. В некоторых фреймворках нет произвольных роутов, а используется схема вида /контроллер/экшен/параметры/параметры/. Эта схема позволяет сгенерировать много УРЛ для одной страницы, что негативно отражается на индексировании поисковиками.
Ну вот самый простой пример: допустим в фреймворке все контроллеры лежат в одной папке. В этом случае за несколько лет там может набраться сотня контроллеров и будет тяжело ориентироваться. А Зенд и Симфони позволяют разбить код на отдельные модули, в каждом из которых будут свои контроллеры.
Или неймспейсы: если фреймворк не поддерживает неймспейсы, то работать с кодом из множества классов будет неудобно.
Другой пример - поддержка DI. В зенде 1 кстати было много проблем, связанных с архитектурой, для DI там ничего не было, модели создавались где попало и по всему коду было разбросано new Model_Users.
Или более сложный пример: понадобилось сделать сайт двухязычным. С этим справится не любой фреймворк.
Плюс, предполагается что у авторов "энтерпрайз" фреймворка есть опыт работы с большими проектами и они знакомы с проблемами, которые возникают при их написании.
Еще для "энтепрайза" важна поддержка "стандартов" или чего-то похожего. Ну к примеру, стандарт на автозагрузчик, логгер, итд, чтобы не было такого, что каждая библиотека использует свой логгер и непонятно как их объединять. В Яве, которая считается "энтерпрайзным" языков, есть определенный формально процесс принятия стандартов JSR и самих стандартов довольно много:
https://ru.wikipedia.org/wiki/Java_Community_Process
https://www.jcp.org/en/jsr/all
Ну и вот еще вопрос на англ по теме https://www.quora.com/What-are-the-best-frameworks-for-large-scale-enterprise-web-development-and-why
> Аналогично как мне задать в phpdoc-блоке некое виртуальное свойство, допустим $__clone_shit, которое тоже возвращает именно конечного потомка (static::class), а не Animal.
Никак, и есть ощущение, что ты там что-то переусложняешь. Также, имена, начинающиеся с 2 подчеркиваний, зарезервированы для использования разработчиками PHP и ты не должен свои поля называть так.
Сами "виртальные" свойства, создаваемые через __get, можно описать с помощью @proeprty, но магических методов по возможности лучше избегать. Лучше сделать реальное свойство.
>>992590
Это константа, определенная где-то в коде проекта. Тебе стоит начать с изучения синтаксиса языка PHP.
>>992274
Хороший совет в общем-то, но тут бы он не помог.
>>992157
>>992123
Скобки ставят, чтобы писать более сложные выражения и чтобы отделить переменную от окружающего текста. Ставить круглые нельзя, именно фигурные надо. Можно без них в некоторых случаях, описано в мануале http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
>>992153
Я бы советовал не заморачиваться с вставкой сортировки в URL, а просто использовать аргументы ?sort=.... (то есть у нас есть одна страница списка студентов, и разные параметры ее отображения), а если ты вставляешь аргументы в URL - то обеспечить чтобы каждая страница была доступна ровно по одному URL. С точки зрения поисковиков в общем это плохо, что есть куча страниц с разными URL, но с одними и теми же данными, просто выводящимися в разном порядке (это однако можно исправить добавлением метатега canonical).
>>992134
А что такое "энтерпрайз"? Это большие, сложные проекты, которые обычно развивают годами, соответственно нужно чтобы фреймворк был пригоден для их написания.
Также, предполагается что в хорошем фреймворке есть какие-то готовые решения для часто встречающихся задач. Ну например, роутер. В некоторых фреймворках нет произвольных роутов, а используется схема вида /контроллер/экшен/параметры/параметры/. Эта схема позволяет сгенерировать много УРЛ для одной страницы, что негативно отражается на индексировании поисковиками.
Ну вот самый простой пример: допустим в фреймворке все контроллеры лежат в одной папке. В этом случае за несколько лет там может набраться сотня контроллеров и будет тяжело ориентироваться. А Зенд и Симфони позволяют разбить код на отдельные модули, в каждом из которых будут свои контроллеры.
Или неймспейсы: если фреймворк не поддерживает неймспейсы, то работать с кодом из множества классов будет неудобно.
Другой пример - поддержка DI. В зенде 1 кстати было много проблем, связанных с архитектурой, для DI там ничего не было, модели создавались где попало и по всему коду было разбросано new Model_Users.
Или более сложный пример: понадобилось сделать сайт двухязычным. С этим справится не любой фреймворк.
Плюс, предполагается что у авторов "энтерпрайз" фреймворка есть опыт работы с большими проектами и они знакомы с проблемами, которые возникают при их написании.
Еще для "энтепрайза" важна поддержка "стандартов" или чего-то похожего. Ну к примеру, стандарт на автозагрузчик, логгер, итд, чтобы не было такого, что каждая библиотека использует свой логгер и непонятно как их объединять. В Яве, которая считается "энтерпрайзным" языков, есть определенный формально процесс принятия стандартов JSR и самих стандартов довольно много:
https://ru.wikipedia.org/wiki/Java_Community_Process
https://www.jcp.org/en/jsr/all
Ну и вот еще вопрос на англ по теме https://www.quora.com/What-are-the-best-frameworks-for-large-scale-enterprise-web-development-and-why
> $totalNumberOfBills
лучше $billCount или просто $count
> if ($numberOfBills > $totalNumberOfBills) {
> $numberOfBills = $totalNumberOfBills;
Это лучше сделать через min/max вместо if
Решено верно.
>>991964
Да, php и sql. Посмотри ОП пост, там есть уроки и задания по теме.
>>991932
У тебя форматирование очень странное, что за лестница?
Также, проверка на дабл стоит в конце и до нее выполнение просто не дойдет - раньше сработает одно из 3 предыдущих условий. В группе if/elseif/else сработать может только один блок.
Попробуй вместо mt_rand поставить даблы и посмотреть, что выйдет.
>>991867
Ставь команды echo и выводи значение переменных, чтобы видеть как имено выполняется цикл. Может это поможет.
>>991859
Здесь нужно выполнить расчет кредита, но для 3 разных комбинаций начальных условий. Здесь нам помогут функции. Мы создаем свою функцию расчета кредита, которая на вход получает его условия, а на выходе например возвращает сумму выплат. И вызываем эту функцию 3 раза, получаем 3 суммы выплат, которые и выводим на экран.
>>991856
Урок в ОП посте читал про установку PHP? Ставишь PHP на компьютер, после чего ставишь IDE ("среду" как ты называешь) вроде Netbeans, Eclipse PDT (беспл), PhpStorm (платно) и в них настраиваешь расположение интерпретатора, чтобы они могли его запускать.
>>991822
Хороший совет. utf8mb4 это какая-то улучшенная версия utf8 в MySQL, как я помню.
>>991821
utf8mb4 наверно. utf8_unicode_ci это не кодировка, а collation (набор правил сравнения и сортировки строк): http://gahcep.github.io/blog/2013/01/05/mysql-utf8/
Лучше брать utf8, так как завтра у тебя встретится какой-нибудь хитрый символ в тексте, и не получится его сохранить. Также utf8 самая популярная кодировка и менее популярные кодировки могут какими-то функциями просто не поддерживаться. Хотя сейчас ситуация противоположная - регулярки (RLIKE) в MYSQL не поддерживают utf-8.
>>991789
Не надо так писать. Просто человек что-то не понял, а ты его сразу в необучаемые записал.
>>991702
Что-то по ссылке не виден код.
> $totalNumberOfBills
лучше $billCount или просто $count
> if ($numberOfBills > $totalNumberOfBills) {
> $numberOfBills = $totalNumberOfBills;
Это лучше сделать через min/max вместо if
Решено верно.
>>991964
Да, php и sql. Посмотри ОП пост, там есть уроки и задания по теме.
>>991932
У тебя форматирование очень странное, что за лестница?
Также, проверка на дабл стоит в конце и до нее выполнение просто не дойдет - раньше сработает одно из 3 предыдущих условий. В группе if/elseif/else сработать может только один блок.
Попробуй вместо mt_rand поставить даблы и посмотреть, что выйдет.
>>991867
Ставь команды echo и выводи значение переменных, чтобы видеть как имено выполняется цикл. Может это поможет.
>>991859
Здесь нужно выполнить расчет кредита, но для 3 разных комбинаций начальных условий. Здесь нам помогут функции. Мы создаем свою функцию расчета кредита, которая на вход получает его условия, а на выходе например возвращает сумму выплат. И вызываем эту функцию 3 раза, получаем 3 суммы выплат, которые и выводим на экран.
>>991856
Урок в ОП посте читал про установку PHP? Ставишь PHP на компьютер, после чего ставишь IDE ("среду" как ты называешь) вроде Netbeans, Eclipse PDT (беспл), PhpStorm (платно) и в них настраиваешь расположение интерпретатора, чтобы они могли его запускать.
>>991822
Хороший совет. utf8mb4 это какая-то улучшенная версия utf8 в MySQL, как я помню.
>>991821
utf8mb4 наверно. utf8_unicode_ci это не кодировка, а collation (набор правил сравнения и сортировки строк): http://gahcep.github.io/blog/2013/01/05/mysql-utf8/
Лучше брать utf8, так как завтра у тебя встретится какой-нибудь хитрый символ в тексте, и не получится его сохранить. Также utf8 самая популярная кодировка и менее популярные кодировки могут какими-то функциями просто не поддерживаться. Хотя сейчас ситуация противоположная - регулярки (RLIKE) в MYSQL не поддерживают utf-8.
>>991789
Не надо так писать. Просто человек что-то не понял, а ты его сразу в необучаемые записал.
>>991702
Что-то по ссылке не виден код.
Сможет все же кто-нибудь помочь в этом вопросе?
https://ideone.com/PusPco
Получилось нихуя не элегантно. Разучился думать уже. Если он имел совсем без функций, то как-то так. Если еще и форич убрать, то там немного по другому.
> и до нее выполнение просто не дойдет - раньше сработает одно из 3 предыдущих условий
Блин а ведь и правда. Что с можно с этим сделать?
Я просто не понимаю, где я не верно мыслю. Сейчас ход моих мыслей такой
1)Делается массив с данными всех одноклассников
2) Перебераю массив с помощью foreach
3) if рост анона < одноклассника, то прибавляю к количеству высоких +1
Думаешь ты правильно.
Вижу ты реализацию поправил - больше похоже на правду. Вернее правда и есть, ты ошибся в написании кода. Обрати внимание, что у тебя условие сразу же точкой с запятой закрывается.
>Где токсичность-то? Запостил код в тред - получил комментарии.
Одно дело просто код прокомментировать, а другое дело подчеркивать, что я основы ООП не знаю. Это как раз переход на личности.
По поводу его замечаний я ничего не сказал. С чем-то согласен, с чем-то нет, а что-то еще не изучал.
>Тебе ведь пишут, почему лучше так или иначе сделать, а не просто предлагают верить на слово.
Да в том то и дело, что он просто пишет как считает лучше и мне вопросы задает, как будто я в Синагогу пришел.
Вот в голове не укладывается, почему когда я постил говнокод, его никто не комментировал, а когда стал более-менее что-то читаемое писать, то у меня вдруг все плохо стало.
Я согласен, на некоторую критику так же токсично реагирую, как пишут мне, я тоже человек и иногда у меня бомбит.
У тебя неправильный код. Посмотри:
> if ($anonHeight < $height);
Что делает этот if? if пишется в виде if (условие) { действия; } , а у тебя действия не указаны, и он ничего не делает в итоге (увы PHP позволяет такие кривые if писать).
В итоге у тебя $number++ выполняется на каждом шаге и просто считает число учеников.
То есть идея решения правильная, но написано неверно.
Ответ тоже неверный так как там по моему не 9, а 8 человек которые выше.
>>992699
Первый пик неправильный по моему.
Я тебе советую следовать PSR-4 и сделать для моделей и контроллеров отдельные неймспейсы. Иначе где гарантия что не будет конфликта имен?
Второй выглядит верно. Проверь регистр букв в composer.json - он там важен, я помнб человек написал PSR-4 вместо psr-4 и ничего не работало.
Вот документация, если что https://getcomposer.org/doc/04-schema.md#autoload
Путь надо указывать от корня проекта, то есть не models, а App/models. И кстати в PSR-4 неймспейсы (models) обычно пишутся с большой буквы (хотя в PSR это не указано).
>я основы ООП не знаю
Все верно, не знаешь.
>переход на личности.
Не льсти себе, какая из тебя "личность"
>почему когда я постил говнокод, его никто не комментировал
Потому что безнадежные дебилы никому не интересны.
>а когда стал более-менее что-то читаемое писать
А не совсем безнадежные - уже другое дело.
>иногда у меня бомбит.
>иногда
Какие мы оптимисты.
>>992735
Ой. Спасибо. Я случайно поставил ; не заметил. http://ideone.com/8SYQnk а вот так тогда?
> Вот в голове не укладывается, почему когда я постил говнокод, его никто не комментировал, а когда стал более-менее что-то читаемое писать, то у меня вдруг все плохо стало.
Ну может некогда было, может не интересно, я не знаю, почему. Может я тогда просто устал каждому второму новичку разъяснять про устаревшие функции. Нельзя из этого сделать вывод, что код был лучше или хуже.
>>992732
Переставить блоки местами, так как условия проверяются сверху вниз.
>>992731
Тебе бы надо работу с массивами подучить. Не используешь готовые функции
- для поиска индекса элемента можно использовать array_search, а чтобы элементоы в массиве шли с правильными индексами - array_values.
- для нахождения границ диапазона - min, max
- для взятия куска массива - array_slice
>>992684
Не знаю, что делать. Проверь настройки, может в настройках проекта как-то можно кодировку указать.
Вот тут например у VS Code есть настройка encoding https://code.visualstudio.com/docs/getstarted/settings
>Тебе бы надо работу с массивами подучить. Не используешь готовые функции
Ты хоть смотри, что в треде происходит. Суть была в том, чтобы без функций это сделать.
Делал. Ставлю NetBeans. Посмотрю, что на ней.
>Может я тогда просто устал каждому второму новичку разъяснять про устаревшие функции.
Да понятно, что это дело добровольное дело, я ни от кого ничего не требую.
Я стараюсь уважительно общаться, не всегда получается, так что в конкретном случае извините, если кого-то обидел.
Или им только самому переменные давать надо? И если так, то какой командой это сделать? foreach - это цикл, а он мне не нужен
*элементы массива
Массив состоит из элементов, у каждого есть индекс и значение. Индекс может быть строкой или целым числом, значение - любым типом данных. Массив оптимизирован для быстрого получения значений по индексу.
Я просто вопрос по идиотски задал. Я делаю команду рандом и мне выдает в ответе рандомный индекс. А мне нужен текст
Тебе надо получить из массива значение элемента (в котором текст) по индексу. Для этого есть квадратные скобки, посмотри урок.
Я сделал сам не знаю как. Но я совершенно не понимаю почему это работает http://ideone.com/ZXQSLU
Подскажите где проблема? Задача про школьника и айфон. У меня получается немного не так, как в ответе.
Мы не скидываем решения задач, но ты можешь показать то, что смог написать, и спросить, если что-то непонятно.
>>992798
А что именно не понятно?
>$paymentTotal += $monthlyPayment - $creditBalance;
Тут ошибка. Мб еще где есть, первое попавшееся даю.
Вообще с командой вывода массива. То есть если я хочу в ответ содержание, то мне надо брать команду в фигурные скобки. А если хочу индекс, то не брать?
квадратные*
А сам как давно и как вкатился?
1) Я сделал пустой массив $line[] и туда поместил $randomText, так? Но почему я не могу сразу сделать массив $line[$randomText]? Потому что $randomText уже часть другого массива?
2) Не понимаю как можно все написать в одну строчку с помощью точек, а не команды implode
Делаю $file->moveTo("/files/$name") - получаю ошибку "Upload target path is not writable".
Делаю $file->moveTo(__DIR__ . "/files/$name") - получаю ошибку "is not valid a uploaded file".
Имя, естественно, это имя исходного файла $name = $file->getClientFilename();
А нет, не правильно
> Я сделал пустой массив $line[] и туда поместил $randomText, так? Но почему я не могу сразу сделать массив $line[$randomText]?
Код $line[$randomText] - это вообще-то поиск элемента в массиве с индексом из переменной $randomText
Чтобы создать массив с одним элементом надо писать $x = [ $randomText ]; Элементу при этом будет присвоен индекс 0.
Потому советую пересмотреть примеры кода из урока.
Также, есть мануал (немного сложный) http://php.net/manual/ru/language.types.array.php
Что касается вопроса, если бы у нас сразу были все 4 слога, нам массив был бы и не нужен. Тот же проблема в том, что у нас слоги генерируются в цикле, по одному за раз. И надо где-то их сохранить до конца цикла. Для этого хорошо подходит массив - перед циклом создаем пустой массив (класть в него пока нечего), на каждом шаге генерируем и добавляем в него слог, а после цикла склеиваем содержимое массива в строку.
У тебя кстати код не совсем правильный, так как implode стоит внутри цикла. Зачем его делать несколько раз? Достаточно склеить слоги один раз.
> Потому что $randomText уже часть другого массива?
$randomText это строка и ее можно сохранить в любое число массивов. Нет такого правила, что содержимое переменной можно скопировать только в один массив.
> Не понимаю как можно все написать в одну строчку с помощью точек, а не команды implode
Для этого нужно перечислить все слоги явно. Например, так:
$result = $line[0] . $line[1] . ... $line[3];
Но не очень понятно, чем это лучше implode. Ведь если мы захотим сделать не 4, а 8 слогов, нам руками придется переделывать эту строчку.
> Я сделал пустой массив $line[] и туда поместил $randomText, так? Но почему я не могу сразу сделать массив $line[$randomText]?
Код $line[$randomText] - это вообще-то поиск элемента в массиве с индексом из переменной $randomText
Чтобы создать массив с одним элементом надо писать $x = [ $randomText ]; Элементу при этом будет присвоен индекс 0.
Потому советую пересмотреть примеры кода из урока.
Также, есть мануал (немного сложный) http://php.net/manual/ru/language.types.array.php
Что касается вопроса, если бы у нас сразу были все 4 слога, нам массив был бы и не нужен. Тот же проблема в том, что у нас слоги генерируются в цикле, по одному за раз. И надо где-то их сохранить до конца цикла. Для этого хорошо подходит массив - перед циклом создаем пустой массив (класть в него пока нечего), на каждом шаге генерируем и добавляем в него слог, а после цикла склеиваем содержимое массива в строку.
У тебя кстати код не совсем правильный, так как implode стоит внутри цикла. Зачем его делать несколько раз? Достаточно склеить слоги один раз.
> Потому что $randomText уже часть другого массива?
$randomText это строка и ее можно сохранить в любое число массивов. Нет такого правила, что содержимое переменной можно скопировать только в один массив.
> Не понимаю как можно все написать в одну строчку с помощью точек, а не команды implode
Для этого нужно перечислить все слоги явно. Например, так:
$result = $line[0] . $line[1] . ... $line[3];
Но не очень понятно, чем это лучше implode. Ведь если мы захотим сделать не 4, а 8 слогов, нам руками придется переделывать эту строчку.
Cпасибо за подробное объяснение.
Не можешь пожалуйста посмотреть правильно ли я сделал расшифровку? >>993379
Что-то сейчас sqlfiddle не открывается, показывает белую страницу, я может потом еще гляну.
По твоему вопросу: это задача на джойны, и она решается примерно так:
- джойним несколько таблиц, получаем все возможные комбинации записей из них
- отсеиваем ненужные записи условиями ON, WHERE
- группируем если надо
- считаем аггрегатные данные для групп
Ну тут очевидно, что надо взять таблицу пользователей и к ней приджойнить статистику лайков. Сгруппировать по пользователям, чтобы в каждой группе были лайки, относящиеся к одному пользователю. Дальше возникают довольно сложные вопросы, вроде "если у нас есть группа, как посчитать число уникальных пользователей-получателей-лайков в ней, при условии что они могут повторяться" или "как посчитать число взаимных лайков (то есть записей, где 2 поля равны) в группе".
Для ответа на первый вопрос надо изучить возможности MySQL:
https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html
http://www.mysql.ru/docs/man/Group_by_functions.html
Что касается взаимных лайков - дам такую подсказку. Как посчитать число записей в группе, соответствующих определенному условию (например x < 10) ? Примерно так:
x < 10 вернет 0 или 1
SUM(x < 10) найдет число записей, где условие выполняется
>>993379
Сделано верно. Только переменные не надо называть с большой буквы и имя ab тоже неудачное. Можно наверно было назвать decodeTable.
Каждый раз, когда ты создаешь объект PDO (или объект-обертку над PDO), устанавливается новое соединение. Конечно, это неправильно. Нужно создать единственный объект и использовать его везде. И желательно без глобальных переменных и синглтонов, это описано в моем уроке по DI https://github.com/codedokode/pasta/blob/master/arch/di.md
В простейшем случае можно просто создать объект PDO через new, а затем создать все объекты, которые его используют и передать в них этот объект.
В более сложном случае нужен DI контейнер.
composer - это менеджер зависимостей (зависимостей другого уровня), он только помогает установить сторонние библиотеки и настроить автозагрузку.
Спасибо. Забыл поменять название на что-то более хорошее прежде чем показывать. Это я для себя по быстрому делал. Я просто еще не мог разобраться, потому что думал, что можно вписать array_flip($cipher) и мне все станет как раньше, лол
>>993548
Ну мне не полноценный фреймворк нужен. Я поставил https://medoo.in только для работы с бд. Один файл, 30КБ и запросы выглядят теперь нормально:
$row = $db->select('content', '*', ['id' => 3200517]);
array(1) { [0]=> array(1) { ["name"]=> string(3) "hui" } }
К первому элементу первого массива я могу обратиться array[0]. Как мне обратиться к значению name и получить "hui"?
array[0]['name']
А не, вспомнил, это array_push. Если я правильно понял, то echo выводит значение переменной, а var_dump информацию о переменной?
> ты не должен додумывать, что будет возвращен именно объект Cat
Если я использую метод класса, который всегда конструирует мне объект этого класса, то я могу быть уверенным, что
get_class(Cat::get_instance()) === 'Cat'
>>992715
> начинающиеся с 2 подчеркиваний
Ты докопался до реализации, забив на суть.
Мдэ, надо стандарт для php-блоков дополнять и добавлять его в Idea. Мне правда нужен @return static и @property static $_blahblah
> почему программисты такие токсичные
Потому что профа такая. Чтобы быть хорошим программистом надо иметь много времени, потраченного на программирование. Для этого надо иметь много свободного времени. А для этого надо не иметь девушку. А это тащит за собой неудовлетворенность, агрессивность и последующее желание самоутвердиться за счёт кого-то другого. Ну и сублимация, куда уж без нее?
Есть два варианта решения:
1. за линейку проходишься по списку и сравниваешь, увеличивая счетчик = O(N)
2. за логарифм сортируешь функцией sort, потом за линейку проходишься до первого элемента выше нужного. Вычитаешь из кол-ва элементов позицию этого элемента. От O(log N) до O(log N + N), но тут как повезёт
class Student{
public function getStudent(){...}
}
$student = new Student;
class Profile{
public function getProfile(Student $student){...}
}
Ошибка must be an instance of , типо не создан экземпляр
Помогите дауничу
Сейчас имею такои методы в Database.php(раньше они висели в студенте)
>connectDb()
>addInfo()
>updateInfo()
>loadInfo($user_id)
>getInfoAllStudents()
>getInfoOnID()
>foundUserId()
>getFullName($user_id)
>searchID($search_query)
А ты читал https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md ?
Класс Student просто хранит информацию об одном студенте. А класс для работы с БД - содержит методы для записи и загрузки этих студентов из БД. Хотя, есть паттерн active record, когда обе этих задачи совмещаются в одном классе.
Нет, ненормально. Если в файле определяется класс или функции, то кода на верхнем уровне (не внутри функций) там быть не должно.
Ну и с точки зрения логики это ведь неправильно. Почему сессия должна создаваться в тот момент, когда подключается этот класс? тут логики нет. А если я подключу класс, но не буду создавать объект? сессия все равно запустится.
Как же тогда решить проблему с заголовками, ведь сессия или куки выполняется до вывода любых заголовков
Потому что ты видимо опечатался и вместо $word5[$text5] например $word5[$text4]. Там длины массивов разные у 5го и 4го.
>>993874
Что-то у тебя не то с архитектурой.
Точно. Я же вроде проверил текст 20 раз, а в итоге все равно не заметил
Можно начинать сессию в начале метода в контроллере. Но вообще, я не уверен что сессии нужны в задаче на студентов.
class Student{
public function getStudent(){
echo "getStudent";
}
}
$student = new Student;
class Profile{
public function getProfile(Student $student){
var_dump($student);
}
}
$profile = new Profile;
$profile->getProfile($student);
Готово 3/4. Делать админку сложнее всего. Пока код прошу не рейтить, там дохуя косяков, я еще не все исправил, что нарейтили раньше и накопились новые. Добью комментарии и буду рефракторить. Какие же уебищные названия у методов, все в разном стиле. Ну хоть папку с представлениями в порядок привел.
Куда делись ответы на этот пост? Я попал в другую вселенную? Пожалуйста, скажите, что вы их тоже видели.
Там был совет сдампить $_FILES, но я не могу это сделать потому, что получаю страницу с исключением слима. Как это вывести?
Можно сделать var_dump(...);die();
Иначе Слим перехватывает вывод (через ob_start - http://php.net/manual/ru/ref.outcontrol.php).
Сдампить я советовал не только FILES , но и объект Слима, представляющий файл.
Ошибка была из-за того, что, во-первых, я перед загрузкой проверял, что код ошибки равен 1, который означает, что файл превышает размер допустимый настройками php, а не 0. Вот я дубовая голова, перепутал индексы! И во-вторых ещё, загружал файл с размером больше допустимого.
<a href="#listOfBonusBlock" data-url="/main-page/json/bonuses/DEPOSIT/" class="jsonBlock btn btn-xs m-b-xs btn-default " title="">Бонусы за депозит</a>
Конкретно не понимаю, что делает: data-url
К слову сказать не нашел и доки по данному атрибуту.
А на странице http://ru.casinoglobal.info/main/#listOfBonusBlock
происходит очень интересная магия: при переключении кнопок.
Как это возможно реализовать.
Пфф, даже быдло посылает роскомпозор на хуй и качает киношки с запрещенных рашкой трекеров, а ты не можешь?
>когда в 2к17 году запилил гостевуху на пхп
Побыстрому наклепал комментирование каждой цитаты.
Есть идея, чтобы была возможность постить не только текст, еще картинки и ссылки на видео.
Ща бы званого башорг изобретать.
Алсо, ты же понимаешь, что пилишь абсолютную хуйню? Лучше бы как все, борду пилил.
Поясни.
Был файл с цитатками, интересными мне, который трудно читать, всё в одну строку https://github.com/grigoryMovchan/AphorismCMS/blob/master/support_scripts/doc/quotes.txt Сначала я его распарсил, потом сделал приятно представление, а потом захотел все это добро как-то организовать и понеслось
Чем борда лучше? Почему хуня? Я точно знаю, что это интересно нескольким анонам в нофап-треде.
Propel: http://propelorm.org/
>>993931
>>994157
> Пока код прошу не рейтить
И смысл тогда этих постов? Анон, этот тред - не твой ежедневник, хватит вниманиеблядствовать.
>>994176
Вот в нофап-тред и кидай свои ежедневные отчёты и скрины.
>А ты читал https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md ?
Мда. Пойду...почитаю..
>И смысл тогда этих постов?
Мне интересно кто что сейчас пилит. А с точки зрения экзистенциализма, надо делать так, как хочешь чтобы все поступали. А я не прочь почитать чужие отчетики. Программирование, это не только абстрактные сущности, но и люди, мотивация.
Мне, например, не интересно в очередной раз читать как у кого-то массивы или циклы в голове не укладываются, но я им ничего не пишу.
>Вот в нофап-тред и кидай свои ежедневные отчёты и скрины.
Обязательно, держу в курсе.
Собственно, вот моя позиция, ничьи права я не нарушаю, за сим уведомляю, что буду продолжать. Можете жаловаться модератору, ваше право, если забанят меня - тогда другой разговор.
Алсо, можете скрывать посты, которые только лично вам не нравятся, есть такая кнопка. Анон, будь терпимее.
Я возмущён постом того анонимуса.
От лица всех анонимусов ссу ему в ебало приношу глубочайшие извинения.
Ну а кроме шуток, мотивируй, это интересно, такое нужно.
В конфу нашу еще пропишись, там нужны такие замотивированные, как ты.
Твои посты достаточно интересны на фоне остального. Я вот думаю свой фреймворк пилить, может тоже буду тут срать по этой теме.
>мотивируй
Я акцентировал на том, что меня мотивирует, когда кто-то пишет о своих поделках. А то без этого создается впечатление, что только задачки про циклы решают или рокетсайнс занимаются, а по середине ничего.
"массив совпадений с регулярным выражением" - я думаю, это массив, который заполняет функция preg_match. Если она нашла в тексте совпадение с регулярным выражением, то она сохраняет в массив такие элементы:
- под индексом 0 сохраняется часть строки, совпавшая с регуляркой
- под индексом 1 - часть строки, совпавшая с первыми круглыми скобками в регулярке, если они есть
- под индексом 2 - со вторыми круглыим скобками, если они есть
Посмотри мануал еще:
- http://php.net/manual/ru/function.preg-match.php
- http://php.net/manual/ru/regexp.reference.subpatterns.php
podor'; DROP DATABASE;
И я не шучу. Как обмазаться базовой безопасностью такого проекта?
Вот код: https://jsfiddle.net/e2auoa54/1/ . Сначала идёт аякс, потом функция, в которой значок не работает, а потом функция, в которой работает.
Такое ощущение, что в глаза ебусь и не вижу что-то очевидное. Может вы посмотрите свежим взглядом?
В первой функции ты $.ajax вызываешь, а не свой метод ajax().
Член юпитера, какой же это омерзительнейший код, гори ты в аду, если не перепишешь
>Мне кажется, тут кто-то кого-то не понял.
Расписываю подробно.
Есть файл manager.php, который первым делом проверяет, залогинился ли юзер. Если нет - редирект на login.php. Если да, то отрисовывает страницу, на которой есть кнопки управления.
Допустим, одна из них "Показать таблицу". По нажатии на неё срабатывает js-скрипт, хватает введённые данные и отправляет их аяксом (type:"POST") в show.php. Там проверки на правомочность запроса нет, он просто выполняется. В начале скрипта стоит только
header("Content-type: text/plain; charset=utf-8");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
Нужно поставить проверку?
Блин, ну точно же.
А что именно омерзительно в коде? Я самоучка, поэтому указывать на ошибки обычно некому. Что переписать?
Ты сделал неправильно. Ты защитил страницу, которая просто выводит кнопку, а обработчик запроса, который и выполняет действие - никак не защитил. Что мешает злоумышленнику сразу отправить POST запрос к скрипту show.php?
Важно представлять как работает веб-сайт, как взаимодействует браузер (клиент) и сервер. Все, что происходит за пределами сервера - полностью контролируется злоумышленником и он может слать любые запросы.
Попробуй сам нарисовать схему взаимодействия и ты увидишь слабые места:
клиент сервер
GET manager.php -> проверка -> вывод формы
POST show.php -> выполнение действия
Взаимодействие сетевых программ удобно изображать с помощью вот такой вот диаграммы последовательности UML https://ru.wikipedia.org/wiki/Диаграмма_последовательности
Я советую попробовать изобразить сеанс работы в админке с помощью такой диаграммы, и слабые места увидишь, и заодно правильно рисовать такие вещи научишься. На диаграмме можно сделать 2 вертикальных линии (браузер и сервер), браузер отправляет GET/POST запросы, а сервер проверяет авторизацию, выполняет какие-то действия, возвращает HTML страницы.
Хорошо, попробую.
Сейчас у меня страница с проверкой реализована так (html сократил): https://jsfiddle.net/co4gmL3L/
Там html-код выполняется только если авторизация пройдена. Но так вообще можно его оформлять? Обычно строки выводятся через эхо или принт. У меня работает.
Плохо перемешивать логику обработки запроса и HTML-код. Почитай про шаблоны: http://webcache.googleusercontent.com/search?q=cache:www.phpinfo.su/articles/practice/shablony_v_php.html&ie=UTF-8&gws_rd=cr&ei=u9ciWajNEorM6ATC1bP4DQ
(даю ссылку на кеш так как сайт накрылся).
https://gist.github.com/codedokode/9424217
Наверно, наилучшем решением будет хранение файлов на отдельном сервере, но поскольку это учебное задание, можно обойтись и одним, и просто переименовывать php\html файлы. Значит, нужно будет иметь в бд как и оригинальное имя, так и то которое храниться на сервере?
Чтобы получить оригинальное имя при скачивании можно добавлять в ссылку атрибут download="...", но это, наверно, не очень надёжно. Лучше при скачивании самому выставлять заголовки с помощью php. Это хорошо тем, что можно выставить в заголовке filename оригинальное имя файла, я прав?
>борьба с загрузкой HTML-файла: можно загружать файлы на отдельный от основного домен, можно при скачивании выставлять правильные заголовки, которые заставят браузер скачать файл, а не открыть его как веб-страницу (Content-Disposition: attachment, Content-Type не содержащий text/html)
>Content-Type не содержащий text/html
Почему нельзя содержать такой тип? Страница будет открываться в любом случае?
Я затрудняюсь на этом моменте потому, что чтобы выставить заголовки нужно вызвать отдельный контроллер, который будет это делать, вместо того чтобы давать прямую ссылку на файл. Здесь нету, какой-то серьёзной проблемы, просто я не хочу делать отдельный контроллер. Может здесь можно что-нибудь посоветовать? Хотя конечно вряд ли.
Генерацию директорий к файлу можно сделать проще - независимо от всего генерировать новую директорию для файла, и если файл с таким именем уже существует в директории, то рекурсивно заново вызвать эту функцию. Искать в ручную файлы, наверно, будет не удобно, но в любом бы случае пришлось бы первым делом смотреть путь в бд, если какой-то файл понадобиться.
Я правильно делаю, что передаю роутер в шаблон, чтобы сгенерировать ссылку?
https://github.com/someApprentice/filehosting/blob/master/public/index.php#L25
https://github.com/someApprentice/filehosting/blob/master/templates/index.phtml#L24
А как делается мультиязычность? Это, наверно, делается с помощью middleware - сначала определяется какой язык должен быть, а потом передаются данные на нужном языке. Где эти данные лучше хранить? В бд или константах прямо в коде (например EN_TITLE, RU_TITLE)?
https://gist.github.com/codedokode/9424217
Наверно, наилучшем решением будет хранение файлов на отдельном сервере, но поскольку это учебное задание, можно обойтись и одним, и просто переименовывать php\html файлы. Значит, нужно будет иметь в бд как и оригинальное имя, так и то которое храниться на сервере?
Чтобы получить оригинальное имя при скачивании можно добавлять в ссылку атрибут download="...", но это, наверно, не очень надёжно. Лучше при скачивании самому выставлять заголовки с помощью php. Это хорошо тем, что можно выставить в заголовке filename оригинальное имя файла, я прав?
>борьба с загрузкой HTML-файла: можно загружать файлы на отдельный от основного домен, можно при скачивании выставлять правильные заголовки, которые заставят браузер скачать файл, а не открыть его как веб-страницу (Content-Disposition: attachment, Content-Type не содержащий text/html)
>Content-Type не содержащий text/html
Почему нельзя содержать такой тип? Страница будет открываться в любом случае?
Я затрудняюсь на этом моменте потому, что чтобы выставить заголовки нужно вызвать отдельный контроллер, который будет это делать, вместо того чтобы давать прямую ссылку на файл. Здесь нету, какой-то серьёзной проблемы, просто я не хочу делать отдельный контроллер. Может здесь можно что-нибудь посоветовать? Хотя конечно вряд ли.
Генерацию директорий к файлу можно сделать проще - независимо от всего генерировать новую директорию для файла, и если файл с таким именем уже существует в директории, то рекурсивно заново вызвать эту функцию. Искать в ручную файлы, наверно, будет не удобно, но в любом бы случае пришлось бы первым делом смотреть путь в бд, если какой-то файл понадобиться.
Я правильно делаю, что передаю роутер в шаблон, чтобы сгенерировать ссылку?
https://github.com/someApprentice/filehosting/blob/master/public/index.php#L25
https://github.com/someApprentice/filehosting/blob/master/templates/index.phtml#L24
А как делается мультиязычность? Это, наверно, делается с помощью middleware - сначала определяется какой язык должен быть, а потом передаются данные на нужном языке. Где эти данные лучше хранить? В бд или константах прямо в коде (например EN_TITLE, RU_TITLE)?
Вообще, код плохой. Ты пишешь большой сложный скрипт не пытаясь разбить его на функции, сделать более читаемым. У тебя там гигантские вложенные ифы.
Надо это переделывать. А то сейчас чтобы просто понять как это работает, надо долго вчитываться. Код должен быть проще:
проверить авторизацию;
если (нет авторизации) {
редирект и завершить скрипт;
}
если (параметры верные) {
выполнить действие, отдать ответ и завершить скрипт;
}
вывести страницу;
Прочитал. Да, до шаблонов я ещё не добрался. Попробую переписать код, используя шаблоны.
Да, если ты можешь все то же сделать без неё
Сука, теперь придется MVC админки выносить в отдельную папку /admin, чистить модели /app от методов /admin, дрочиться с неймспейсами, чтобы юзать в /admin методы из модели /app
Пиздец, это еще на неделю. Ну все лучше чем в доту играть.
Или не надо админку отдельно выносить, мне только засранный контроллер не нравится, можно ведь только его раздеть
Тут лучше для каждого раздела админки сделать свой контроллер. Контроллеры можно поместить в отдельную папку и например унаследовать от какого-то общего предка, если надо.
Насчет моделей - не уверен, что с ними что-то надо делать. Обычно не требуется делать отдельные модели для админки, но если у тебя не соблюдается MVC и модели это на самом деле контроллеры то конечно возможно варианты.
Спасибо. Тоже так считаю.
Чуть переписал роутер, чтоб он искал контроллеры в другой папке, если первый элемент пути в ссылке будет 'admin'. Осталось раскидать этот жирный контроллер. А модели и правда нет смысла разделять, только сильнее запутаю.
Чет я просто сначала запаниковал и расстроился. Теперь не все так плохо выглядит.
>если у тебя не соблюдается MVC и модели это на самом деле контроллеры то конечно возможно варианты
Оп говорит, что я там хуйни наворотил и вообще не шарю, но вроде модели и контроллеры не перепутаны, методы моделей инкапсулировал как мог.
Еще нужны отдельная папка для шаблонов. И может быть для CSS/JS если в админке другие стили.
Есть таблица с 50 колонками и пару тысячу строк. Что лучше, загрузить большой объем данных и обрезать его в пхп, или делать много запросов и получать маленький объем данных?
да.
Слушай, я по случаю тоже сижу в ноуфап треде. Может сверстаем ОПу годный сайт на бутстрапе? Будем его поддерживать вводить новые фишки, такой-то опыт командной работы.
Переделал.
- Перешёл с простого mysql на PDO.
- Перенёс отрисовку страниц в отдельные файлы шаблонов, типа manager.html.
- Переписал скрипт проверки, убрав вложенность условий. Работает теперь так: если нет куков - отфутболить. Если есть, проверить соответствие в базе, не прошло - отфутболить. Если всё ок - ничего не делать.
- Сам скрипт перенёс в отдельный файл protection.php https://jsfiddle.net/3v48dsgo/
В управляющих скриптах страниц мало что осталось. Например, manager.php:
// Скрипт проверки
include('./protection.php');
// Это используется при отрисовке шаблона
$user_id = $userdata['user_id'];
// Загружаем шаблон
include('./template/manager.html');
Собираюсь внести include('./protection.php'); в начало каждого управляющего скрипта на php, но сначала надо их немного привести в порядок.
Ну как теперь? Стало лучше? Что ещё не по фен-шую?
оп, красавчик, спасибо что ты есть....
>сверстаем
Я сейчас не собираюсь в верстку углублятся, освоил азы бутстрапаи и пока хватит. После цитатника надо Зандстра добить, а это надолго. Да и личного интереса нет, не цеплет меня идея.
Алсо, смотрел исходники его сайта, там класов и пространства имен нет, каждая функция в отдельном файле. Первый раз такое вижу. Я особо не пытался разбираться, но вроде, с бэком у него все норм раз работает https://nofap.ru/files/nofap-28.02.2k17.tar.bz2 Да и дизайн пойдет, менять его голый бустрап, что шило на мыло.
Собственно схуяли?
Работа сдалана вот и заебись.
Я щас сайт для заказа шлюх сделаю и в портфолио он у меня будет красоваться повыше остальных из-за сложности.
Я свой в гитхабе собираюсь оставить, то в очередь платформа для коллекции любых цитаточек. Да и если название достойное придумтаь, то можно и цитатки оставить, благо там нормальные авторы.
А нофа да, спецефический ресурс, случайному человеку даже объяснять будет стыдно нахуя он нужен. Хот видно, что работы там дохуя проделано.
>Я свой в гитхабе собираюсь оставить
Правда, я там почти все оставляю, чтоб прогресс было видно, а его видно. Только в ридми пишу, что говно, но переделывать не собираюсь
>>995093
Мало данных. Не понятно что тебе нужно сделать и с чем. Постоянно показывать всю таблицу пользователям? Один раз обработать данные?
>Постоянно показывать всю таблицу пользователям? Один раз обработать данные?
Ну смотри, у меня на сайте есть несколько хтмл таблиц, разбитые по категориям. Я могу сделать один запрос к БД и уже в пвп разрезать всю огромную таблицу на несколько мелких. А могу сделать несколько запросов с выборкой только нужной категории под каждую таблицу на сайте.
Будь у меня таблица в БД не такая большая с кучей текста, я бы сказал, что мне абсолютно похуй. Но теперь я хочу знать, что лучше один запрос, который возвращает дохуя, или штук десять разных, которые возвращают каждый 1/10 всей таблицы.
Лучше разрезать. Так будет легче потом вносить изменения.
Плюс еще есть ограничения
https://dev.mysql.com/doc/refman/5.7/en/packet-too-large.html
Я даун. Спасибо.
Пишу код (пхп, цсс, жс) и копирую каждый раз его по фтп на веб сервер (на хостинге, там вся начинка сервера принадлежит хостеру и я о ней не парюсь), а потом проверяю в браузере, чего получилось. И мне таки надоело каждый раз делать это копирование с подтверждением замены. Да ещё фтп каждые 10 минут отваливается.
Вижу стулья:
1) У нас в конторе в качестве шлюза используется виндовс сервер. На нём стоит iis7. Настроить на нём сайт так, чтобы он был виден из интернета (по ип) и редактировать код прямо на нём. Плюс доустановить пхп, майскул и т.д.
2) Поставить там же Топ сервер или Денвер и получить всё это из коробки.
3) Поднять вируалку в сети, воздвигнуть на неё ЛАМП, сделать проброс портов (или что там нужно) и таки получить доступ из интернета к тестовому сайту.
Эти стулья - действительно стулья, или всё делается как-то иначе? Мне нужно избавиться от лишних действий при разработке.
В шторме есть возможность работы с проектом, находящимся на удаленной машине. К примеру через SFTP. Минусы - синхронизация на локалке (выкачка) может быть долгой. В остальное же время сидишь и работаешь, как с локальным дерьмецом.
Лучший вариант все же развернуть виртуалку (глянь в сторону вагранта кстати) у себя с шаред папкой под проект. Настройки окружения, конечно, с тебя.
Можно еще прямо на локалке все ебенить, это уж если тебе так нравится.
Я обычно пишу скрипт для выгрузки на сервер на bash, чтобы не надо было вручную ничего делать. В случае с FTP, есть консольная программа lftp, которая умеет синхронизировать файлы с учетом даты изменения, единственный ее недостаток - она всегда возвращает нулевой код ошибки независимо от результата копирования.
Если ты не лобишь консоль то может можно найти или купить программу, которая копирует файлы одной кнопкой.
Копировать файлы на удаленный сервер довольно неудобно и конечно лучше развернуть копию проекта локально. Если он не работает под виндой, можно попробовать поставить линукс без GUI в виртуалбокс.
Насчет IIS - я с ним не работал, но как минимум htaccess в нем не поддерживается и тебе придется писать конфиг аналогичный тому что на линукс-сервере.
спс, я так понял что простые переменные можно без {}, а что то сложнее типо свойств или массивов уже нет.
Сейчас, файлы ни как не загружались и на выходе было лишь сообщение об ошибке без указания причин. Display_errors выставлен в on, error_reporting E_ALL. Как оказалось, размер файлов всего лишь немного не умещался в upload_max_filesize и post_max_size. Так вот, должны ли приходить оповещения о причинах, при подобных проблемах, или я что-то упустил?
>>995043
Ну наконец то, сука, основной объем осилен. Разделить контроллеры было проще, чем я думал, больше с фронтконтроллером пёхался.
Мимошизик
Почитай http://php.net/manual/ru/features.file-upload.php особенно этот раздел http://php.net/manual/ru/features.file-upload.errors.php
Превышение размера не вызывает генерацию ошибки, просто в поле error проставляется соответствующий код. Это уже твоя задача его проверять и выводить сообщения.
>>995733
Да
>>995673
> preg_split('/\r\n/iu',
Вот здесь проблема. Конец строки может обозначаться по-разному в зависимости от ОС и настроек редактора. В блокноте на винде он обозначается как последовательность 2 символов \r\n, но в том же линуксе или маке по умолчанию используется только \n. Соответственно твоя программа может работать некорректно если используется не тот формат конца строки. Лучше разбивать строки по \n, а символ \r (если он есть) вырезать с помощью trim().
Определить самую длинную строку можно короче, если использовать array_map: сделать массив длин строк и взять максимальное значение в нем.
> for ($j = 0; $j < count($sentences); $j ++) {
Тут лучше использовать foreach
>>995672
shared folders (когда на хосте поднимается NFS- или SMB-сервер, а в виртуалке - клиент) могут работать намного медленнее обычных папок. Я исопльзую скрипт, который находит изменившиеся файлы с помощью find, создает список и копирует их через rsync.
Хотя может на быстром железе разница не так заметна.
Один запрос наверно быстрее, но я не очень понимаю, зачем тебе столько данных, ведь пользователь вряд ли способен просмотреть 50 000 записей на одной странице, да и браузер будет тормозить наверно.
>>995142
Теперь тебе надо осваивать функции (вспомогательный код надо писать в виде функций, которые можно вызвать), и конфиги (чтобы не копипастить данные подключения к БД).
Вообще, ты неправильно учишься. Вот зря ты спешишь браться за базы данных и делать сайт, когда ты не освоил функции и не научился разбивать код на кусочки, а не писать стеной. Я бы тебе конечно посоветовал почитать комментарии к задаче про студентов из ОП поста, там очень много советов. А пока ты пропустил много важных тем и берешься за сложное, не выучив основы.
Я как-то видел большой проект, написанный человеком который как раз не выучил основы, там был адский код, огромные стены кода, в которых просто разобраться нереально. Потому что человек не научился писать читаемый, понятный код, а писал как умел. Есть кстати книга "Совершенный код", если захочется, можешь почитать, хотя она не про PHP написана, но большинство советов подойдут и к PHP.
Я кстати всем анонам советую посмотреть эту книгу. Есть разница между написанием простых скриптов из 20 строчек и больших приложений, и книга вам про нее расскажет. Там есть хорошая аналогия - нельзя строить небоскреб теми же инструментами, что и собачью будку, нужен другой подход.
> header("Location: status_codes.php?result=401"); exit();
Это тоже что-то ненормальное. Редиректить надо на страницу логина. А если ты хочешь выдать ошибку с кодом N то ее надо выдавать сразу, а не через редирект, так как редирект это код 302. Это ошибка, если ты например вместо выдачи страницы с кодом 404 редиректишь на какой-то URL вроде /not_found.php.
>>995060
templates внутри views смотрится странно. Может быть это layouts?
>>995032
Что значит "загрузить картинку на URL"? Отправить POST-запрос с картинкой по протоколу HTTP? Тогда нужен HTTP-клиент, например curl, который встроен в PHP, или библиотека Guzzle, которая сделана с использованием ООП.
Один запрос наверно быстрее, но я не очень понимаю, зачем тебе столько данных, ведь пользователь вряд ли способен просмотреть 50 000 записей на одной странице, да и браузер будет тормозить наверно.
>>995142
Теперь тебе надо осваивать функции (вспомогательный код надо писать в виде функций, которые можно вызвать), и конфиги (чтобы не копипастить данные подключения к БД).
Вообще, ты неправильно учишься. Вот зря ты спешишь браться за базы данных и делать сайт, когда ты не освоил функции и не научился разбивать код на кусочки, а не писать стеной. Я бы тебе конечно посоветовал почитать комментарии к задаче про студентов из ОП поста, там очень много советов. А пока ты пропустил много важных тем и берешься за сложное, не выучив основы.
Я как-то видел большой проект, написанный человеком который как раз не выучил основы, там был адский код, огромные стены кода, в которых просто разобраться нереально. Потому что человек не научился писать читаемый, понятный код, а писал как умел. Есть кстати книга "Совершенный код", если захочется, можешь почитать, хотя она не про PHP написана, но большинство советов подойдут и к PHP.
Я кстати всем анонам советую посмотреть эту книгу. Есть разница между написанием простых скриптов из 20 строчек и больших приложений, и книга вам про нее расскажет. Там есть хорошая аналогия - нельзя строить небоскреб теми же инструментами, что и собачью будку, нужен другой подход.
> header("Location: status_codes.php?result=401"); exit();
Это тоже что-то ненормальное. Редиректить надо на страницу логина. А если ты хочешь выдать ошибку с кодом N то ее надо выдавать сразу, а не через редирект, так как редирект это код 302. Это ошибка, если ты например вместо выдачи страницы с кодом 404 редиректишь на какой-то URL вроде /not_found.php.
>>995060
templates внутри views смотрится странно. Может быть это layouts?
>>995032
Что значит "загрузить картинку на URL"? Отправить POST-запрос с картинкой по протоколу HTTP? Тогда нужен HTTP-клиент, например curl, который встроен в PHP, или библиотека Guzzle, которая сделана с использованием ООП.
> можно обойтись и одним, и просто переименовывать php\html файлы. Значит, нужно будет иметь в бд как и оригинальное имя, так и то которое храниться на сервере?
Переименовывать надо в любом случае, так как могут быть файлы с одинаковыми именами, с нечитаемыми символами, файлы с названием .htaccess которые переопределяют настройки веб-сервера, .gitignore которые влияют на git и тд.
> Чтобы получить оригинальное имя при скачивании можно добавлять в ссылку атрибут download="...", но это, наверно, не очень надёжно. Лучше при скачивании самому выставлять заголовки с помощью php. Это хорошо тем, что можно выставить в заголовке filename оригинальное имя файла, я прав?
Нельзя, так как в HTTP заголовках можно использовать только символы ASCII (не так давно добавили возможность указывать кодировку и вставлять символы не из ASCII). атрибут download работает только в относительно новых браузерах. По моему в комментариях к задаче написано, что самый надежный способ, работающий везде - это поместить имя файла в конец URL.
Отдавать файл в идеале лучше всего веб-сервером, а не PHP, опять же это по моему описано в комментариях к задаче.
> Почему нельзя содержать такой тип? Страница будет открываться в любом случае?
Не помню, почему. Может стоит проверить экспериментально? Если attachment не указан, то браузер смотрит на Content-Type и если тип ему знаком, пытается отобразить содержимое, иначе предложит сохранить. А если attachment указан, то по идее должен сразу предложить сохранить.
Может это защита от какой-нибудь уязвимости, когда злоумышленник загрузит HTML-файл и попытается как-то с его помощью украсть например куки пользователя пользуюсь тем, что файл находится на том же домене что и сайт. Не помню.
> Здесь нету, какой-то серьёзной проблемы, просто я не хочу делать отдельный контроллер. Может здесь можно что-нибудь посоветовать?
Есть такие варианты:
- отдавать средствами PHP
- ставить заголовки и передавать отдачу серверу через X-Sendfile (Апач), X-Accel-redirect (nginx). Это обычно используется для учета и ограничения скачиваний, когда перед скачиванием запускается php скрипт.
- написать правила для веб-сервера так, чтобы по определенной ссылке он отдавал файл с указанным в ней именем. Вроде такого: ссылка имеет вид /download/1.txt/название.txt и по ней отдается файл, хранящийся под именем 1.txt.
> я не хочу делать отдельный контроллер.
Ну это слабый аругмент. Есть возможность скачивания файла, логично для нее сделать контроллер.
> Генерацию директорий к файлу можно сделать проще - независимо от всего генерировать новую директорию для файла
На каждый файл свою папку генерировать - не очень эффективно, рекурсивный обход всех файлов будет медленнее из-за этих папок (хотя я не тестировал, у меня есть такое ощущение). Лучше всего по 100-1000 файлов в папку класть.
> Я правильно делаю, что передаю роутер в шаблон, чтобы сгенерировать ссылку?
Так можно делать, но по моему опыту лучше сделать свой класс-генератор ссылок, это лучше по таким причинам:
- мы передаем в шаблон именно генератор ссылок, а не роутер, который содержит избыточные, ненужные функции
- в своем классе можно дописать дополнительную логику, проверки. Без него эту логику придется размазывать по шаблонам. Явно нарущается какой-то принцип написания хорошего кода (DRY?)
Ну например у тебя код имеет вид
$router->pathFor('download', ['id' => $file->getId()])?>
А могло бы быть
$urlGenerator->getDownloadUrl($file)
Хотя может для маленького проекта это лишнее усложнение. Но мне все же кажется что полезно так сделать.
Вместо переменных для защиты от CSRF удобнее передавать сам объект в шаблон.
> А как делается мультиязычность? Это, наверно, делается с помощью middleware - сначала определяется какой язык должен быть, а потом передаются данные на нужном языке. Где эти данные лучше хранить? В бд или константах прямо в коде (например EN_TITLE, RU_TITLE)?
Не, middleware тут не поможет, надо закладывать в архитектуру.
Стоит наверно сделать разные URL для разных версий страниц, иначе нельзя дать ссылку на страницу на определенном языке и они не будут нормально индексироваться. Википедия напримр использует на каждый язык свой поддомен. Можно использовать и папку в URL.
Насчет БД - есть 2 варианта: либо делать несколько колонок, либо выносить переводимые части в отдельные таблицы (например вида (fileId, language, description)). То есть либо располагать переводы "горизонтально" (в одной строке в разных колонках) либо "вертикально" (в разных строках).
Более того, бывает, что перевода нет. То есть есть статья на одном языке, а на другом языке перевод пока не готов. Или решено его не делать. Нужно решать, что делать в таком случае.
Далее, надо перевести интерфейс и сообщения в коде. Тут решение давно известно - gettext или аналогичный велосипед. Мы оборачиваем все сообщения в вызов функции, например:
echo message($language, 'File uploaded successfully'); // выведет фразу на текущем языке
Затем мы скриптом-сканером извлекаем список фраз и отдаем переводчикам. Они дают нам список переведенных фраз, мы его загружаем в программу и при выводе выбираем нужную фразу.
Как я написал выше, есть расширение gettext для этого. В нем есть функция перевода (с коротким именем _), сделаны форматы файлов для хранения переводов, и есть готовые программы для работы с переводами (например Poedit).
gettext используется не только в PHP, но и в других языках программирования. Советую его изучить.
Далее, в фразы иногда надо подставлять переменные. Например:
- Иван написал новый пост
Подход вроде echo $userName . message($l, 'написал новый пост'); не сработает, так как в некоторых языках имя "Иван" может оказаться в середине или конце фразы, и переводчикам неудобно работать с куском предложения.
Далее мы наткнемся на еще одну проблему. Фразы (внезапно) могут меняться в зависимости от пола, числа предметов:
- Иван загрузил 3 фотографии в альбом
- Маша загрузила 5 фотографий в альбом
И, что еще веселее, формы слов и правила их использования в разных языках разные. Решается это с помощью введения синтаксиса для подстановки переменных в фразы, для выбора варианта слова в зависимости от условий:
echo message($lang, 'Peter has {0, plural, =0{no cat} =1{a cat} other{# cats}}', ['cats' => $cats])
Тут можно изобретать свой синтаксис, а лучше взять готовый из ICU (поддерживается в расширении Intl):
- http://php.net/manual/ru/messageformatter.formatmessage.php
- http://userguide.icu-project.org/formatparse/messages (англ, подробно)
Стандартный формат хорош тем, что переводчики могут быть с ним знакомы, плюс могут быть инструменты для работы с ним. Не вижу особой выгоды изобретать тут велосипед.
Ну еще из мелочей - в разных странах разные форматы вывода дат, дробных чисел (точка или запятая), денежных сумм и валют. Это решается созданием соответствующих функций, или использованием классов из расширения Intl: http://php.net/manual/ru/book.intl.php
В разных языках разные правила сортировки строк. Это описано тут https://github.com/codedokode/pasta/blob/master/php/collation.md
Ну и стоит почитать про Юникод, может там еще какие-то подвохи по мелочи есть. ну например, если ты хочешь написать регулярку для проверки имени, надо учитывать, что имена в разных языках могут содержать символы разных алфавитов. Может тут стоит использовать символьные классы вроде \p{L}.
Еще есть языки, где текст пишется справа налево, а чтобы жизнь медом не казалась, иностранные слова там пишутся слева направо. Соответственно надо изучить возможности HTML/CSS (атрибут dir и соотв-е свойство), а также юникодные символы выбора направления вывода текста.
В общем, простор для изучения тут большой. Начни с gettext и Intl.
> можно обойтись и одним, и просто переименовывать php\html файлы. Значит, нужно будет иметь в бд как и оригинальное имя, так и то которое храниться на сервере?
Переименовывать надо в любом случае, так как могут быть файлы с одинаковыми именами, с нечитаемыми символами, файлы с названием .htaccess которые переопределяют настройки веб-сервера, .gitignore которые влияют на git и тд.
> Чтобы получить оригинальное имя при скачивании можно добавлять в ссылку атрибут download="...", но это, наверно, не очень надёжно. Лучше при скачивании самому выставлять заголовки с помощью php. Это хорошо тем, что можно выставить в заголовке filename оригинальное имя файла, я прав?
Нельзя, так как в HTTP заголовках можно использовать только символы ASCII (не так давно добавили возможность указывать кодировку и вставлять символы не из ASCII). атрибут download работает только в относительно новых браузерах. По моему в комментариях к задаче написано, что самый надежный способ, работающий везде - это поместить имя файла в конец URL.
Отдавать файл в идеале лучше всего веб-сервером, а не PHP, опять же это по моему описано в комментариях к задаче.
> Почему нельзя содержать такой тип? Страница будет открываться в любом случае?
Не помню, почему. Может стоит проверить экспериментально? Если attachment не указан, то браузер смотрит на Content-Type и если тип ему знаком, пытается отобразить содержимое, иначе предложит сохранить. А если attachment указан, то по идее должен сразу предложить сохранить.
Может это защита от какой-нибудь уязвимости, когда злоумышленник загрузит HTML-файл и попытается как-то с его помощью украсть например куки пользователя пользуюсь тем, что файл находится на том же домене что и сайт. Не помню.
> Здесь нету, какой-то серьёзной проблемы, просто я не хочу делать отдельный контроллер. Может здесь можно что-нибудь посоветовать?
Есть такие варианты:
- отдавать средствами PHP
- ставить заголовки и передавать отдачу серверу через X-Sendfile (Апач), X-Accel-redirect (nginx). Это обычно используется для учета и ограничения скачиваний, когда перед скачиванием запускается php скрипт.
- написать правила для веб-сервера так, чтобы по определенной ссылке он отдавал файл с указанным в ней именем. Вроде такого: ссылка имеет вид /download/1.txt/название.txt и по ней отдается файл, хранящийся под именем 1.txt.
> я не хочу делать отдельный контроллер.
Ну это слабый аругмент. Есть возможность скачивания файла, логично для нее сделать контроллер.
> Генерацию директорий к файлу можно сделать проще - независимо от всего генерировать новую директорию для файла
На каждый файл свою папку генерировать - не очень эффективно, рекурсивный обход всех файлов будет медленнее из-за этих папок (хотя я не тестировал, у меня есть такое ощущение). Лучше всего по 100-1000 файлов в папку класть.
> Я правильно делаю, что передаю роутер в шаблон, чтобы сгенерировать ссылку?
Так можно делать, но по моему опыту лучше сделать свой класс-генератор ссылок, это лучше по таким причинам:
- мы передаем в шаблон именно генератор ссылок, а не роутер, который содержит избыточные, ненужные функции
- в своем классе можно дописать дополнительную логику, проверки. Без него эту логику придется размазывать по шаблонам. Явно нарущается какой-то принцип написания хорошего кода (DRY?)
Ну например у тебя код имеет вид
$router->pathFor('download', ['id' => $file->getId()])?>
А могло бы быть
$urlGenerator->getDownloadUrl($file)
Хотя может для маленького проекта это лишнее усложнение. Но мне все же кажется что полезно так сделать.
Вместо переменных для защиты от CSRF удобнее передавать сам объект в шаблон.
> А как делается мультиязычность? Это, наверно, делается с помощью middleware - сначала определяется какой язык должен быть, а потом передаются данные на нужном языке. Где эти данные лучше хранить? В бд или константах прямо в коде (например EN_TITLE, RU_TITLE)?
Не, middleware тут не поможет, надо закладывать в архитектуру.
Стоит наверно сделать разные URL для разных версий страниц, иначе нельзя дать ссылку на страницу на определенном языке и они не будут нормально индексироваться. Википедия напримр использует на каждый язык свой поддомен. Можно использовать и папку в URL.
Насчет БД - есть 2 варианта: либо делать несколько колонок, либо выносить переводимые части в отдельные таблицы (например вида (fileId, language, description)). То есть либо располагать переводы "горизонтально" (в одной строке в разных колонках) либо "вертикально" (в разных строках).
Более того, бывает, что перевода нет. То есть есть статья на одном языке, а на другом языке перевод пока не готов. Или решено его не делать. Нужно решать, что делать в таком случае.
Далее, надо перевести интерфейс и сообщения в коде. Тут решение давно известно - gettext или аналогичный велосипед. Мы оборачиваем все сообщения в вызов функции, например:
echo message($language, 'File uploaded successfully'); // выведет фразу на текущем языке
Затем мы скриптом-сканером извлекаем список фраз и отдаем переводчикам. Они дают нам список переведенных фраз, мы его загружаем в программу и при выводе выбираем нужную фразу.
Как я написал выше, есть расширение gettext для этого. В нем есть функция перевода (с коротким именем _), сделаны форматы файлов для хранения переводов, и есть готовые программы для работы с переводами (например Poedit).
gettext используется не только в PHP, но и в других языках программирования. Советую его изучить.
Далее, в фразы иногда надо подставлять переменные. Например:
- Иван написал новый пост
Подход вроде echo $userName . message($l, 'написал новый пост'); не сработает, так как в некоторых языках имя "Иван" может оказаться в середине или конце фразы, и переводчикам неудобно работать с куском предложения.
Далее мы наткнемся на еще одну проблему. Фразы (внезапно) могут меняться в зависимости от пола, числа предметов:
- Иван загрузил 3 фотографии в альбом
- Маша загрузила 5 фотографий в альбом
И, что еще веселее, формы слов и правила их использования в разных языках разные. Решается это с помощью введения синтаксиса для подстановки переменных в фразы, для выбора варианта слова в зависимости от условий:
echo message($lang, 'Peter has {0, plural, =0{no cat} =1{a cat} other{# cats}}', ['cats' => $cats])
Тут можно изобретать свой синтаксис, а лучше взять готовый из ICU (поддерживается в расширении Intl):
- http://php.net/manual/ru/messageformatter.formatmessage.php
- http://userguide.icu-project.org/formatparse/messages (англ, подробно)
Стандартный формат хорош тем, что переводчики могут быть с ним знакомы, плюс могут быть инструменты для работы с ним. Не вижу особой выгоды изобретать тут велосипед.
Ну еще из мелочей - в разных странах разные форматы вывода дат, дробных чисел (точка или запятая), денежных сумм и валют. Это решается созданием соответствующих функций, или использованием классов из расширения Intl: http://php.net/manual/ru/book.intl.php
В разных языках разные правила сортировки строк. Это описано тут https://github.com/codedokode/pasta/blob/master/php/collation.md
Ну и стоит почитать про Юникод, может там еще какие-то подвохи по мелочи есть. ну например, если ты хочешь написать регулярку для проверки имени, надо учитывать, что имена в разных языках могут содержать символы разных алфавитов. Может тут стоит использовать символьные классы вроде \p{L}.
Еще есть языки, где текст пишется справа налево, а чтобы жизнь медом не казалась, иностранные слова там пишутся слева направо. Соответственно надо изучить возможности HTML/CSS (атрибут dir и соотв-е свойство), а также юникодные символы выбора направления вывода текста.
В общем, простор для изучения тут большой. Начни с gettext и Intl.
Кстати, я делал небольшой двухязычный сайт и участовал в интернационализации большого проекта. Там, я помню, даже была сделана отдельная админка для переводчиков.
>>994588
Могу для начала дать несколько уроков: https://github.com/codedokode/pasta/tree/master/security
>>994395
Не очень, так как юзер мог переключиться на другую вкладку или отойти от компьютера. Хотя если уведомления неважные (Маша поставила лайк) то можно и так.
>>994354
Из описания непонятно. Приведи примеры ссылок что ли.
А так, может что-то с .htaccess?
На проверку.
http://ideone.com/sPOexIДоллары в рубли
http://ideone.com/tMu8IN Кубики
http://ideone.com/P3xI5r Миллион в банке
http://ideone.com/xutDDU Айфон
http://ideone.com/6WlyG3 Средняя оценка
http://ideone.com/INkXnO Рост анона
http://ideone.com/3YTUk6 Ответ на любой вопрос
http://ideone.com/GMEMJi Шифровка
Я знаю, что нужно вешать метод в контроллере на сабмит в форме, но как сформировать URL?
>> Генерацию директорий к файлу можно сделать проще - независимо от всего генерировать новую директорию для файла
>На каждый файл свою папку генерировать - не очень эффективно, рекурсивный обход всех файлов будет медленнее из-за этих папок (хотя я не тестировал, у меня есть такое ощущение). Лучше всего по 100-1000 файлов в папку класть.
Чтобы посчитать сколько файлов в текущей папке нужно сначала определить есть ли текущая папка вообще (на случай если файл загружается впервые), затем посчитать сколько в этой папке файлов, и определить есть ли там файл с таким именем. Получается довольно большой блок условий. А если генерировать новую директорию в любом случае, то этот блок сократиться только до проверки существования файла с таким именем а если каждый раз ещё и переименовывать файл, то можно обойтись и без неё. Рекурсивный обход файлов будет долгим в любом случае.
>>996051
>Пытаюсь учить SLIM. Допустим есть поле для ввода и кнопка, по нажатию на которую я хочу формировать новый URL вида site.com/entered_text
>Я знаю, что нужно вешать метод в контроллере на сабмит в форме, но как сформировать URL?
В форме ставишь action="/entered_text" и в контроллере обрабатываешь пост-запрос $app->post('/entered_text', ...).
>И еще поясните, как правильно в MVC - где строить запрос к бд, в модели или в контроллере?
Зависит от архитектуры. Обычно всё делают в модели.
Ненене, это какая-то ересь.
Во-первых, у меня вообще какой-то инфернальный пиздец в строке появляется после нажатия на энтер в текстовом поле. Да, в форме стоят невидимые поля CSRF, но я их не прошу выводиться нигде.
Во-вторых, если я сюда $app->post('/', 'HomeController:postHome'); в адресс поставлю какой-то текст (как вообще я этот текст из формы вытащу в файл роутов?), то этот пост уже будет обрабатываться не по моему изначальному адресу. Госпаде, ну что за пиздец накрутили, я уже полностью запутался.
Отклеилось
Решил сделать скрины, а то явно непонятно объясняю. Роуты - контроллер - вью
Ну так я не знаю, что писать в action и в postHome метод.
Что значит зачем? 99% сайтов со строкой поиска по своей базе так делают, чтобы было удобнее очевидно. Вот пример: в форме на сайте ввел текст - получил его в URL. Как сделать так же?
Так а причем тут урл? Поиск осуществляется по базе, после чего пользователю выдаются результаты/результат, или редиректится на единственный результат например.
А вообще тема поиска по сайту - больная мозоль у всех, нихуя не изич.
>Поиск осуществляется по базе, после чего пользователю выдаются результаты/результат, или редиректится на единственный результат например.
РЕЗУЛЬТАТА НА 123 НЕТ. Нет, понимаешь? Введи 321 или 927384658728346неп9арш7 и это все уйдет в урл. Так что дело не в поиске, а в том, как засунуть это в URL на подобие вот таких сайтов.
Если уж хочешь урл, то это searchQuery или подобный этому параметр. Находится в урле по той причине, что по канонам форма поиска отправляется гет запросом и, как ты должен знать, все параметры в адресную строку для гетов и попадают. Судя по скринам у тебя post запрос, поэтому и нет нихуя. Хочешь получить - осуществляй из контроллера редирект по урлу с установленным параметров.
>>996075
Все гораздо интереснее там. И чем обширнее база и критерии поиска - тем веселее.
Согласен, пост не по канонам для поиска, поэтому я переделаю в гет, чтобы было не /name, а ?name=name. Но тогда вылезает другая проблема: какого хрена у меня в урл лезут эти скрытые поля и как их убрать оттуда, оставив при этом проверку CSRF?
хз что там интереснее. Если ты делаешь поиск именно по контенту, то делается именно так. А контент весь обычно хранится в бд. В итоге всё сводится именно к этому запросу.
Ну, мне было интересно.
Как только перед тобой встает необходимость реализации полнотекстового поиска по сайту (будь то даже имена пользователей) база уже почти бесполезна, будет работать как дерьмо. Тащишь значит готовое решение, сфинкс например, индексируешь им свой терабайты данных, охуеваешь. Потом расширяются критерии поиска - расширяется индексация, добавляются новые индексы. Это все еще и обновлять своевременно надо, а то будет по устаревшему говну искать. В целом да, не особо тяжело, но проблем с ним много обычно. Ну это из моей практики, почти всегда с фултекстом нужно было реализовывать. А без фултекста я только по анкетам юзеров делал на сайте знакомств, там да, и без этого всего обошлось.
>>996077
Честно не знаю.
Могу только сказать, что если у тебя этот гет маршрут ни в коем случае не меняет данные на сервере и безопасен, то csrf там не нужен по сути своей.
>csrf там не нужен по сути своей
Ок, убрал.
Остается последний вопрос. Как передать переменную из контроллера в Twig темплейт?
Сам разобрался.
>CountPage
>showLinkPage
>getLinkSort
Куда этоти методы тулить в студентах? Ну не в класс студент же и не в контоллер, так как там вычисления производятся. Хелпер тоже не для этого.
>>995672
Решил обойтись существующим винсервером. Запустил на нём OpenServer, прописал домен и алиас для него. С самого сервера сайты открываются. А с другого (в той же локальной сети) - нет. Блядь. Со вчерашнего дня настраиваю - не работает. Что там не так - в душе не ебу. Веб сервер должен хоть что-то показывать. Блядь, зла не хватает, заебало, блядь, блядь, блядь, как же заебало всё нахуй блядь.
Отлично, в какую модель? У нас есть 2 класса, Студент и Хелпер. Больше никаких классов. В какую из этих моделей?
Не обязательно все классы строго относить к M, V или C. Можно вполне сделать отдельный вспомогательный класс.
> Больше никаких классов
Можно сделать UrlHelper например.
Дело было в брандмаэре. 80 порт закрыт по умолчанию.
Причем даже типы ресурсов разные. В одном месте это fopen, в другом месте это сетевые стримы из stream_socket_accept.
PHP 5.6 (7.0 есть, но на нём я не тестировал)
Почему?
В этом случае почему-то не срабатывает <?= $number?>.
Как исправить? Нужно что-то как-то экранировать?
> Вот здесь проблема
Переделал - https://3v4l.org/ilZQt
И вот еще считалка https://3v4l.org/vjliq
>Вообще, ты неправильно учишься.
Честно говоря, такой ответ сильно демотивирует.
Я пытался учиться "классическим способом", когда берёшь толстенную книгу-кирпич и выучиваешь первую главу. А потом делаешь к ней упражнения. Потом выучиваешь вторую. И делаешь упражнения. Потом выучиваешь третью. И так всю книгу. Но вот нихрена у меня не получилось освоить таким образом. Это нужно иметь железную армированную жопу, чтобы всё проработать, понять и запомнить. Это нудно, бесконечно и требует конского терпения. И практического толка от этого никакого. Потому что выучил ты книгу - а тебе говорят "пошёл нахуй, у нас тут паттерны, фреймворки, гит и прочее, чего в книге нет. Вот ещё десять таких же кирпичей, выучишь - приходи".
Нужно, как минимум, параллельно работать над настоящими проектами. Иначе эти знания уйдут в песок и забудутся. После зазубренного "Идеального программирования" можно идти преподавать это программирование, но не работать.
Плюс, карьера вида "два года буду учить в вузе, потом подрабатывать стажёром, потом диплом, потом мидл, а через 10 лет, к 26 годам - тимлид" мне не грозит. Потому что возраст давно не тот и на работу программистом никто не возьмёт (на любую должность). Так что, пишу для себя.
У меня другой способ обучения:
1. Сформулировать, чего хочу и придумать, как это реализовать в целом.
2. Гуглить примеры и копипастить из них.
3. Хуячить код.
4. Когда программа начинает работать и делать всё, что от неё было нужно (по самому минимуму) начинаю переписывать, упрощать, делать "защиту от дурака", работать над дизайном. Параллельно почитываю всякие душеспасительные статьи и гайды.
Работая по этой схеме, каждый следующий проект получается лучше, чем предыдущий. Да, знаю, мой код - говно. Но по другому я не могу. Ну не могу я прочитать учебник английского и начать тут же шпарить на нём с выговором коренного жителя Бристоля.
>Это ошибка, если ты например вместо выдачи страницы с кодом 404 редиректишь на какой-то URL вроде /not_found.php.
Не совсем понял. В скрипте проверяется наличие куков и совпадение их содержимого с содержимым базы. При отрицательном ответе редиректит на страницу, которая смотрит причину редиректа и показывает соответствующую ошибку. Ладно, может и не прав. Объяснять, где именно, не надо - это пока мне не нужно.
>Вообще, ты неправильно учишься.
Честно говоря, такой ответ сильно демотивирует.
Я пытался учиться "классическим способом", когда берёшь толстенную книгу-кирпич и выучиваешь первую главу. А потом делаешь к ней упражнения. Потом выучиваешь вторую. И делаешь упражнения. Потом выучиваешь третью. И так всю книгу. Но вот нихрена у меня не получилось освоить таким образом. Это нужно иметь железную армированную жопу, чтобы всё проработать, понять и запомнить. Это нудно, бесконечно и требует конского терпения. И практического толка от этого никакого. Потому что выучил ты книгу - а тебе говорят "пошёл нахуй, у нас тут паттерны, фреймворки, гит и прочее, чего в книге нет. Вот ещё десять таких же кирпичей, выучишь - приходи".
Нужно, как минимум, параллельно работать над настоящими проектами. Иначе эти знания уйдут в песок и забудутся. После зазубренного "Идеального программирования" можно идти преподавать это программирование, но не работать.
Плюс, карьера вида "два года буду учить в вузе, потом подрабатывать стажёром, потом диплом, потом мидл, а через 10 лет, к 26 годам - тимлид" мне не грозит. Потому что возраст давно не тот и на работу программистом никто не возьмёт (на любую должность). Так что, пишу для себя.
У меня другой способ обучения:
1. Сформулировать, чего хочу и придумать, как это реализовать в целом.
2. Гуглить примеры и копипастить из них.
3. Хуячить код.
4. Когда программа начинает работать и делать всё, что от неё было нужно (по самому минимуму) начинаю переписывать, упрощать, делать "защиту от дурака", работать над дизайном. Параллельно почитываю всякие душеспасительные статьи и гайды.
Работая по этой схеме, каждый следующий проект получается лучше, чем предыдущий. Да, знаю, мой код - говно. Но по другому я не могу. Ну не могу я прочитать учебник английского и начать тут же шпарить на нём с выговором коренного жителя Бристоля.
>Это ошибка, если ты например вместо выдачи страницы с кодом 404 редиректишь на какой-то URL вроде /not_found.php.
Не совсем понял. В скрипте проверяется наличие куков и совпадение их содержимого с содержимым базы. При отрицательном ответе редиректит на страницу, которая смотрит причину редиректа и показывает соответствующую ошибку. Ладно, может и не прав. Объяснять, где именно, не надо - это пока мне не нужно.
>у нас тут паттерны, фреймворки, гит и прочее, чего в книге нет
На самом деле нет ничего важнее, чем хорошо наработанный базовый навык кодинга, а все остальное уже прикладывается.
Есть у меня один чувак, он дохуя технологий типа знает, но написать нихуя не может по итогу, спотыкается на любой простейшей вещи.
>Нужно, как минимум, параллельно работать над настоящими проектами.
Это да. Нужен баланс между настоящими проектами и повышением скила. Притом не только во время начального обучения, а всегда.
>Не обязательно все классы строго относить к M, V или C.
А как же парадигма MVC? Меня ОП потом будет ругать!
Паттерн MVC описывает верхний слой абстракции, внутри можешь хоть говно жрать, если желаешь того.
>злоумышленник загружает свой php-скрипт, вызывает его через браузер (http://example.com/uploads/script.php) и получает контроль над сервером
То есть надо как-то делать папку uploads открытой? Или можно сделать маршрут (test.ru/{w+} например), который будет вести на определенный контроллер, и тот уже будет обрабатывать запрос и отображать соответствующий файл? Мой тупой мозг только такую схему понимает.
И можно ли сделать на изображения и остальные файлы две отдельные таблицы в базе данных?
Я бы сделал отдельную модель от которой бы унаследовал другие модели, где нужны перечисленные тобой методы. Ну или можно передать её в конструктор, вместо наследования, забыл как этот паттерн называется.
У меня вьюха записана в пхп и там есть русский текст, и все хорошо, кроме текста из sql
>Есть массив. В нем N+1 чисел. Все числа принимают значения от 1 до N. Нужно указать, какой элемент в массиве повторяется. Повторений может быть сколько угодно. Нужно это сделать за линейное время и константу памяти.
Я так понял условия:
1. Каждый элемент может быть от 1 до N
2. Только один элемент имеет повторения, которых может быть сколько угодно (от 0 до N?)
3. Линейное время https://ru.wikipedia.org/wiki/Временная_сложность_алгоритма
получается, мы можем обратиться к каждому элементу только один раз?
4. >Константа — некоторая величина, не изменяющая своё значение в рамках рассматриваемого процесса.
Мы берем некий кусок памяти перед началом и не превышаем его до конца работы алгоритма?
Запощу пока, завтра попробую.
Объясните по поводу вордпресс, вот допустим я хочу создать определённый функционал на отдельной странице, в котором будут использоваться формы и всё-такое. Как мне это сделать? Просто создать страницу в теме вордпресс, подключить к неё ядро вордпресс и начать писать там свой функционал? Но если так делать то адрес к этой странице будет кривой. А если сделать просто статическую страницу через админку, то на ней не будет работать ПХП код, как поступить?
Зашквар, у нас тут все свои CMS пишут
А ты знаком с хуками в вордпрессе? Они позволяют изменять поведение движка и например добавлять выполнение определенных действий на отдельных страницах.
Также, в вордпрессе есть шорткоды - некоторые делают нестандартные элементы через них.
Наконец, еще по моему есть возможность использовать отдельный php-шаблон для отдельной страницы.
В общем, если ты еще не читал документацию для разработчиков, то самое время этим заняться.
>>996851
> получается, мы можем обратиться к каждому элементу только один раз?
Нет, ты не совсем так понял "O-нотацию". Эта нотация вроде O(1), O(N), O(N^2) задает ограничение скорости роста функции. Проще наверно объяснить на примере.
Допустим, время выполнения алгоритма есть O(N^2), где N - объем входных данных. Это значит:
- при больших N (больше определенного числа N0)
- при увеличении объема входных данных в x раз время выполнения алгоритма вырастет не более чем в x^2 раз
Обрати внимание на первый пункт. Ограничение выполняется только при условии что N больше определенного числа N0, а если N меньше, то оно может не соблюдаться. Но если мы будем увеличивать N, то рано или поздно, это условие сработает.
Второй пункт обозначает что O-нотация задает не абсолютные значения (время в секундах в зависимости от размера массива), а как это время изменяется при увеличении объема входных данных. O(1) - значит что при любом объеме входных данных (и при N > N0) время не превышает определенной постоянной величины. O(N) - что время выполнения растет пропрорционально объему входных данных. И так далее.
Если у нас есть 2 алгоритма, со сложностью O(1) и O(N), и дано например N = 10 то нельзя сказать, какой из них быстрее. Можно только сказать что при росте N рано или поздно второй алгоритм окажется медленнее.
Потому сложности O(N), O(N + 1) O(2xN + 1) - это одно и то же. Так как они все растут линейно, и скорость их роста, хоть она и разная, но не меняется со временем. А вот у O(N^2) скорость роста увеличивается со временем, потому это уже другая сложность.
Я попытался это изобразить на графике. Видно что первая (синяя) функция ограничена горизонтальной линией, и при стремлении N к бесконечности она не превышает ее. Значит, сложность первого алгоритма ограничена O(1) (хотя сама пунктирная линия не обязательно соответствует графику функции y = 1, а вполне может быть y = 10, но O(10) и O(1) это одно и то же). То есть мы можем сказать, что при увеличении объема входных данных первый алгоритм будет работать примерно за такое же время.
Вторая функция со временем начинает возрастать почти линейно, и при стремлении N к бесконечности не пересекает наклонную линию. Это значит, что сложность алгоритма линейная, O(N) и время выполнения при больших N увеличивается пропорционально объему входных данных.
Возвращаясь к твоей задаче:
- ты можешь обращаться к элементу сколько угодно раз, но при увеличении объема входных данных время выполнения должно расти линейно.
> Мы берем некий кусок памяти перед началом и не превышаем его до конца работы алгоритма?
При увеличении объема входных данных потребление памяти не должно расти (разумеется, массив с входными данными при этом не учитывается). То есть, если твой алгоритм например делает копию входрного массива, то это условие уже не выполняется. Но если твой алгоритм например создает массив из тысячи элементов - это допустимо, лишь бы его размер не превышал этой тысячи ни при каких условиях.
А ты знаком с хуками в вордпрессе? Они позволяют изменять поведение движка и например добавлять выполнение определенных действий на отдельных страницах.
Также, в вордпрессе есть шорткоды - некоторые делают нестандартные элементы через них.
Наконец, еще по моему есть возможность использовать отдельный php-шаблон для отдельной страницы.
В общем, если ты еще не читал документацию для разработчиков, то самое время этим заняться.
>>996851
> получается, мы можем обратиться к каждому элементу только один раз?
Нет, ты не совсем так понял "O-нотацию". Эта нотация вроде O(1), O(N), O(N^2) задает ограничение скорости роста функции. Проще наверно объяснить на примере.
Допустим, время выполнения алгоритма есть O(N^2), где N - объем входных данных. Это значит:
- при больших N (больше определенного числа N0)
- при увеличении объема входных данных в x раз время выполнения алгоритма вырастет не более чем в x^2 раз
Обрати внимание на первый пункт. Ограничение выполняется только при условии что N больше определенного числа N0, а если N меньше, то оно может не соблюдаться. Но если мы будем увеличивать N, то рано или поздно, это условие сработает.
Второй пункт обозначает что O-нотация задает не абсолютные значения (время в секундах в зависимости от размера массива), а как это время изменяется при увеличении объема входных данных. O(1) - значит что при любом объеме входных данных (и при N > N0) время не превышает определенной постоянной величины. O(N) - что время выполнения растет пропрорционально объему входных данных. И так далее.
Если у нас есть 2 алгоритма, со сложностью O(1) и O(N), и дано например N = 10 то нельзя сказать, какой из них быстрее. Можно только сказать что при росте N рано или поздно второй алгоритм окажется медленнее.
Потому сложности O(N), O(N + 1) O(2xN + 1) - это одно и то же. Так как они все растут линейно, и скорость их роста, хоть она и разная, но не меняется со временем. А вот у O(N^2) скорость роста увеличивается со временем, потому это уже другая сложность.
Я попытался это изобразить на графике. Видно что первая (синяя) функция ограничена горизонтальной линией, и при стремлении N к бесконечности она не превышает ее. Значит, сложность первого алгоритма ограничена O(1) (хотя сама пунктирная линия не обязательно соответствует графику функции y = 1, а вполне может быть y = 10, но O(10) и O(1) это одно и то же). То есть мы можем сказать, что при увеличении объема входных данных первый алгоритм будет работать примерно за такое же время.
Вторая функция со временем начинает возрастать почти линейно, и при стремлении N к бесконечности не пересекает наклонную линию. Это значит, что сложность алгоритма линейная, O(N) и время выполнения при больших N увеличивается пропорционально объему входных данных.
Возвращаясь к твоей задаче:
- ты можешь обращаться к элементу сколько угодно раз, но при увеличении объема входных данных время выполнения должно расти линейно.
> Мы берем некий кусок памяти перед началом и не превышаем его до конца работы алгоритма?
При увеличении объема входных данных потребление памяти не должно расти (разумеется, массив с входными данными при этом не учитывается). То есть, если твой алгоритм например делает копию входрного массива, то это условие уже не выполняется. Но если твой алгоритм например создает массив из тысячи элементов - это допустимо, лишь бы его размер не превышал этой тысячи ни при каких условиях.
Хочу свою поделку захостить, чтобы анончик потестил. Так же, неплохо было бы набраться опыта в настройке VDS
Юзаю от таймвеб самую дешевую.
Я правильно понял, что либо я страницу с кодом ошибки передаю, либо делаю редирект на страницу для пользователя где "Хуё-моё, администратор уже выехал...", но тогда никаких кодов а заголовке?
Тут ловлю https://github.com/grigoryMovchan/AphorismCMS/blob/master/index.php
Сделал свой класс для исключений, хуй знает что в нем переопределять, может, потом понадобится https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Core/ExceptionMy.php
Даже не спрашивайте, так показалось удобней https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Core/Errors.php
Все что ни возьми - не подходит под хотя бы одно условие: встроенные функции использовать нельзя (время, память), сохранять в массив и проверять по ключу нельзя (память), нельзя решить короче вот...
https://ideone.com/Y83B35
А ты читал https://github.com/codedokode/pasta/blob/master/php/exceptions.md#Страница-ошибки-в-веб-приложениях ?
Некоторые встроенные функции использовать можно. Например, count() работает за O(1) по времени и памяти.
Создавать новые массивы можно при условии что их размер не зависит от входных данных.
Решать эту задачу надо не совсем "в люб", не надо пытаться составить список использованных чисел.
Я кстати вспомнил еще похожую задачу, номер 5 вот отсюда: http://download.yandex.ru/company/shad/exam.pdf ("знаменитость")
(все, кто хочет поломать голову - поломайте)
Также, оформление кода у тебя ужасное. Не придумывай свои правила, а оформляй по PSR-1/2. И давай нормальные имена переменным, не надо экономить тут байты.
>Я правильно понял, что либо я страницу с кодом ошибки передаю, либо делаю редирект на страницу для пользователя где "Хуё-моё, администратор уже выехал...", но тогда никаких кодов а заголовке?
Так, пока понял, что заголовок отдельно - контент отдельно и можно передавать все что угодно после установки заголовка.
Тогда не очень понятно зачем ты придумал свое исключение. Обычно каждый класс исключения обозначает какую-то ситуацию. Ну например, ошибка работы с базой данных (PDOException), ошибка передачи данных по сети (NetworkException) и тд. Что обозначает твой класс?
Также, глобальный обработчик исключений наверно должен ловить все исключения, а не только одного класса. Иначе какой в нем смысл?
Вот ты по моему не понял, как должно это работать.
Также, ты читал мой урок невнимательно. Там написано, что должен делать обработчик исключений - и ты многое из этого не сделал. Например, пользователю не показывается никаких сообщений, информация не фиксируется в логи. Вот как ты будешь узнавать о том ,какие ошибки произошли на сайте, если ты не пишешь логи?
> либо делаю редирект на страницу для пользователя где "Хуё-моё, администратор уже выехал...",
Зачем это нужно? Какой смысл в дополнительном редиректе? Это в каком-то учебнике так советуют?
Название класса тоже неудачное, класс обычно называют в единственном числе. Да и у тебя объект класса не представляет информацию об ошибке и называть его Error нельзя. Подумай внимательно, как он должен называться.
Да, вон над твоим постом бомбит от того какие дураки пытаются пхп учить.
Гитхаб:
https://github.com/Al-faqun/Students/
https://github.com/Al-faqun/Students/releases/tag/1.1
Потыкаться в текущую версию можно тут:
http://shinoa.web44.net/Students/ (обратите внимание, чтобы были включены куки)
Кому интересно, жду ваших багрепортов. Хочу сделать эту программу красивой и продуманной.
В проекте много что вызывает моё недовольство, что хочу изменить:
- deployment. Автоматизация настроек и дополнений. Пока перемещал файлы со своего вина на линь хостинга, пришлось вносить кучу изменений, которые сложно запомнить. Стоит лучше отделить все платформозависимые вещи и настройки.
- обработка инпута пользователя. Мой код был прост и красив, пока я не добавил больше кнопочек, каждая из которой (в виде проверки POSTа) увеличивает размер скрипта процентов на 15; этому должен придти конец. Я пробовал выдумать "контроллер", который бы сократил количество кода до минимума, но это, также как и попытка осмысления MVC, вышли неудачно.
- обработка ошибок расползлась в трёх-четырёх разных местах, я собрал её в одном классе, но он делает лишь половину работы — исключения всё равно могут оказаться где угодно.
- класс Registry. Уродливый, громоздкий, не ре-юзабельный, но всё равно лучше чем скопище глобальных переменных для общих классов. Краем глаза видел в фреймворках классы типа app — наверное, стоит брать с ним пример. Фреймворками не пользовался.
- для работы с БД, возможно, стоит попробовать что-то специализированное типа doctrine2 (не пробовал). Классы генерации SQL исключительно доморощенные и не особо ре-юзабельные.
Что символизирует Хитаги на оппике?
Заебись, уважуха. У меня 2 десятка говноподелок на гитхабе лежит, а пишу все равно хуже. На чем-то раньше уже писал?
>>997128-кун
Я бы не советовал делать страницы ошибок через контроллеры. Ведь ошибка может произойти где-то в базовом классе контроллера или на момент ошибки какие-то компоненты могут быть недоступны. Лучше сделать страницу ошибки как можно проще, без лишних зависимостей, без проверок авторизации и прочего.
Название для исключения тоже неправильное, хотя бы с точки зрения грамматики, my пишется перед exception. Ну и в твоем случае нужно указать конкретно, что это за исключение (например AssertionFailedException). Также, обрати внимание, что в PHP есть готовые исключения: http://php.net/manual/ru/spl.exceptions.php
Название метода тоже неправильное. Ты его назвал "getErrorPage" но он ничего не возвращает - должно быть printErrorPage().
>>997154
Код статуса для роботов, HTML страница для людей.
>>997058
Есть "облако" (1cloud), где ты получаешь линукс-виртуалку, но там надо за все платить - память, процессор, трафик, диск. Выходит в самом минимальном раскладе рублей 250 в месяц наверно, из плюсов - не нужен номер телефона и личные данные, из минусов - платить надо за каждый чих, а трафик фильтруется роскомнадзором.
>>996612
В приложении, когда соединяешься с БД, какую кодировку выставляешь для обмена данными? Когда импортировал, в дампе была правильная кодировка?
http://gahcep.github.io/blog/2013/01/05/mysql-utf8/
http://phpfaq.ru/mysql/charset
Не, ты что-то явно неправильное предлагаешь. Не надо пытаться все методы свалить в один класс (в том числе с помощью наследования).
>>996544
> То есть надо как-то делать папку uploads открытой?
Это зависит от используемого способа раздачи файлов. Если ты хочешь их раздавать без использования PHP, веб-сервером напрямую, то да, надо. Если ты хочешь отдавать файл через PHP или расширение X-Sendfile то открывать папку не требуется.
Там в комментариях к задаче описаны возможные варианты:
- отдавать файл с помощью PHP
- обрабатывать запрос на скачивание в PHP, но затем отдавать заголовок X-Sendfile и поручить саму отдачу файла серверу
- отдавать напрямую веб-сервером
В любом случае, лучше не позволять создавать php-файлы, а также файлы вроде .htaccess, .gitignore и так далее.
> И можно ли сделать на изображения и остальные файлы две отдельные таблицы в базе данных?
Можно, но в чем выгода? Если у обычных файлов и изображений разный набор свойств (колонок) то это пример наследования таблиц и есть 3 паттерна на такой случай: Single Table Inheritance, Class Table Inheritance, Concrete Table Inheritance ( http://design-pattern.ru/ )
>>996518
Парадигма MVC описывает процесс обработки запроса, которым управляет Контроллер, вызывая при необходимости Модель и Вид. Но вполне могут быть какие-то вспомогательные классы, которые просто стоят сбоку и явно к чему-то не относятся.
Но класс, который генерирует URL, наверно можно отнести к Модели, так как это часть логики приложения, и этот класс можно вызывать откуда угодно.
>>996473
>>Вообще, ты неправильно учишься.
> Честно говоря, такой ответ сильно демотивирует.
У меня тут, если посмотреть ОП пост, уже набралось что-то вроде большого курса по PHP. Начиная с основ, продолжая сложными вещами вроде ООП и заканчивая еще более сложными задачами, которые используют смесь технологий, не только PHP. Соответственно, когда человек берется сразу за сложную часть, мне тоже не очень охота объяснять то, что изучалось где-то раньше и что он пропустил.
Вот например у меня есть в ОП посте задача про студентов, на примере которой учатся писать приложения, работающие с формами и базой данных. У нее подробные комментарии, и конечно мне не очень хочется по второму разу их пересказывать тем, кто эту задачу пропустил.
Если и дальше спешить все сделать как можно быстрее, толком не разобравшись, то будет получаться плохой код. А плохой код обозначает высокий процент ошибок, потери времени при попытке вносить изменения. Другие люди будут всеми способами пытаться избежать необходимости в нем разбираться.
Насчет других книг - я их не писал, за их авторов отвечать не могу.
> начинаю переписывать, упрощать, делать "защиту от дурака", работать над дизайном
Это так не работает, у тебя не будет ни сил ни мотивации переписывать большой объем кода и ты его так и оставишь.
> Вот ещё десять таких же кирпичей,
Хороший программист должен много знать и стремиться расширять свой кругозор. У нас в IT нельзя быстренько что-то выучить и потом всю жизнь повторять одни и те же операции.
Не, ты что-то явно неправильное предлагаешь. Не надо пытаться все методы свалить в один класс (в том числе с помощью наследования).
>>996544
> То есть надо как-то делать папку uploads открытой?
Это зависит от используемого способа раздачи файлов. Если ты хочешь их раздавать без использования PHP, веб-сервером напрямую, то да, надо. Если ты хочешь отдавать файл через PHP или расширение X-Sendfile то открывать папку не требуется.
Там в комментариях к задаче описаны возможные варианты:
- отдавать файл с помощью PHP
- обрабатывать запрос на скачивание в PHP, но затем отдавать заголовок X-Sendfile и поручить саму отдачу файла серверу
- отдавать напрямую веб-сервером
В любом случае, лучше не позволять создавать php-файлы, а также файлы вроде .htaccess, .gitignore и так далее.
> И можно ли сделать на изображения и остальные файлы две отдельные таблицы в базе данных?
Можно, но в чем выгода? Если у обычных файлов и изображений разный набор свойств (колонок) то это пример наследования таблиц и есть 3 паттерна на такой случай: Single Table Inheritance, Class Table Inheritance, Concrete Table Inheritance ( http://design-pattern.ru/ )
>>996518
Парадигма MVC описывает процесс обработки запроса, которым управляет Контроллер, вызывая при необходимости Модель и Вид. Но вполне могут быть какие-то вспомогательные классы, которые просто стоят сбоку и явно к чему-то не относятся.
Но класс, который генерирует URL, наверно можно отнести к Модели, так как это часть логики приложения, и этот класс можно вызывать откуда угодно.
>>996473
>>Вообще, ты неправильно учишься.
> Честно говоря, такой ответ сильно демотивирует.
У меня тут, если посмотреть ОП пост, уже набралось что-то вроде большого курса по PHP. Начиная с основ, продолжая сложными вещами вроде ООП и заканчивая еще более сложными задачами, которые используют смесь технологий, не только PHP. Соответственно, когда человек берется сразу за сложную часть, мне тоже не очень охота объяснять то, что изучалось где-то раньше и что он пропустил.
Вот например у меня есть в ОП посте задача про студентов, на примере которой учатся писать приложения, работающие с формами и базой данных. У нее подробные комментарии, и конечно мне не очень хочется по второму разу их пересказывать тем, кто эту задачу пропустил.
Если и дальше спешить все сделать как можно быстрее, толком не разобравшись, то будет получаться плохой код. А плохой код обозначает высокий процент ошибок, потери времени при попытке вносить изменения. Другие люди будут всеми способами пытаться избежать необходимости в нем разбираться.
Насчет других книг - я их не писал, за их авторов отвечать не могу.
> начинаю переписывать, упрощать, делать "защиту от дурака", работать над дизайном
Это так не работает, у тебя не будет ни сил ни мотивации переписывать большой объем кода и ты его так и оставишь.
> Вот ещё десять таких же кирпичей,
Хороший программист должен много знать и стремиться расширять свой кругозор. У нас в IT нельзя быстренько что-то выучить и потом всю жизнь повторять одни и те же операции.
> На самом деле нет ничего важнее, чем хорошо наработанный базовый навык кодинга,
Эта фраза ничего не значит так как ты не определил что такое "базовый навык кодинга". Базовый навык кодинга на PHP поможет сверстать страницу или написать SQL запрос? Поможет правльно давать названяи переменным?
> Есть у меня один чувак, он дохуя технологий типа знает, но написать нихуя не может по итогу, спотыкается на любой простейшей вещи.
Возможно, он знает не сами технологии, а только их названия.
>>996460
> $lines = preg_split('/\n/iu'
хватило бы explode, тут мощь регулярных выражений не особо нужна.
> $char = mb_substr($line, $i, 1);
> if ($char == TRUE) {
Это неправильный код. $char это строка, а не булевское значение (true/false). Это если и работает, то за счет каких-то странностей преобразования строк в булевские значения при сравнении. Попробуй сам прочитать: 'если i-й символ в строке равен TRUE' - как такое может быть?
> И вот еще считалка https://3v4l.org/vjliq
> $counter = NULL;
> $counter++;
Ты кладешь в переменную NULL (обозначающее отстутсвие данных) и потом пытаешься его увеличивать, как будто это число. В переменную надо класть значения одного типа, ноль, а не NULL.
>>996296
А почему это должно работать? Почему <?= внутри строки должен иметь какое-то специальное значение?
Также вместо магического числа 7 лучше использовать константу с понятными именем.
>>996267
Ты наверно где-то работаешь с ними как с числами. То есть берешь их значение, с чем-нибудь складываешь и записываешь обратно. Проверь все места в коде, которые что-то делают с этими полями.
> На самом деле нет ничего важнее, чем хорошо наработанный базовый навык кодинга,
Эта фраза ничего не значит так как ты не определил что такое "базовый навык кодинга". Базовый навык кодинга на PHP поможет сверстать страницу или написать SQL запрос? Поможет правльно давать названяи переменным?
> Есть у меня один чувак, он дохуя технологий типа знает, но написать нихуя не может по итогу, спотыкается на любой простейшей вещи.
Возможно, он знает не сами технологии, а только их названия.
>>996460
> $lines = preg_split('/\n/iu'
хватило бы explode, тут мощь регулярных выражений не особо нужна.
> $char = mb_substr($line, $i, 1);
> if ($char == TRUE) {
Это неправильный код. $char это строка, а не булевское значение (true/false). Это если и работает, то за счет каких-то странностей преобразования строк в булевские значения при сравнении. Попробуй сам прочитать: 'если i-й символ в строке равен TRUE' - как такое может быть?
> И вот еще считалка https://3v4l.org/vjliq
> $counter = NULL;
> $counter++;
Ты кладешь в переменную NULL (обозначающее отстутсвие данных) и потом пытаешься его увеличивать, как будто это число. В переменную надо класть значения одного типа, ноль, а не NULL.
>>996296
А почему это должно работать? Почему <?= внутри строки должен иметь какое-то специальное значение?
Также вместо магического числа 7 лучше использовать константу с понятными именем.
>>996267
Ты наверно где-то работаешь с ними как с числами. То есть берешь их значение, с чем-нибудь складываешь и записываешь обратно. Проверь все места в коде, которые что-то делают с этими полями.
Наклон головы с котиком хорошо рифмуется.
>>996091
Есть еще функция pathinfo()
>>996077
Вообще, CSRF там не нужен (проблемы нет, если злоумышленник заставит пользователя сделать поиск). Более того, он может навредить, если пользователь возьмет и опубликует где-то ссылку на результат поиска, другой пользователь ее откроет и сработает защита из-за того, что у него нет нужных кук.
>>996074
Сайты обычно делают это ради SEO оптимизации, чтобы сделать вид, что у них не одна страница с результатами поиска, а много отдельных страниц с уникальными URL. Не знаю, работает ли это вообще.
Также, возможен редирект, если найден единственный результат. Например, в Википедии, если ввести название статьи в поле поиска, то он на нее редиректит, если же такой статьи нет, то выдает страницу результатов. Попробуй на ней проверить, википедия в плане структуры сайта хорошо сделана (в случае википедии, там реальные страницы и это не имеет ничего общего с сайтами, которые на любое слово готовы сгенерировать отдельную страницу).
>>996070
Сделать это можно через редирект, но это просто попытка обхитрить поисковые системы.
>>996059
> Да, в форме стоят невидимые поля CSRF, но я их не прошу выводиться нигде.
При GET запросе все поля формы добавляются в URL. Как иначе скрипт на сервере их получит? Он их берет из URL, в этом и суть GET запроса. При POST - другое дело, параметры постятся в теле запроса, но зато ты не можешь опубликовать ссылку на результат запроса. Вообще, это основы HTTP, который бы стоило подучить (справедливости ради, нормальных уроков по теме я не видел, а свой все руки не доходят написать).
>>996051
В модели.
Наклон головы с котиком хорошо рифмуется.
>>996091
Есть еще функция pathinfo()
>>996077
Вообще, CSRF там не нужен (проблемы нет, если злоумышленник заставит пользователя сделать поиск). Более того, он может навредить, если пользователь возьмет и опубликует где-то ссылку на результат поиска, другой пользователь ее откроет и сработает защита из-за того, что у него нет нужных кук.
>>996074
Сайты обычно делают это ради SEO оптимизации, чтобы сделать вид, что у них не одна страница с результатами поиска, а много отдельных страниц с уникальными URL. Не знаю, работает ли это вообще.
Также, возможен редирект, если найден единственный результат. Например, в Википедии, если ввести название статьи в поле поиска, то он на нее редиректит, если же такой статьи нет, то выдает страницу результатов. Попробуй на ней проверить, википедия в плане структуры сайта хорошо сделана (в случае википедии, там реальные страницы и это не имеет ничего общего с сайтами, которые на любое слово готовы сгенерировать отдельную страницу).
>>996070
Сделать это можно через редирект, но это просто попытка обхитрить поисковые системы.
>>996059
> Да, в форме стоят невидимые поля CSRF, но я их не прошу выводиться нигде.
При GET запросе все поля формы добавляются в URL. Как иначе скрипт на сервере их получит? Он их берет из URL, в этом и суть GET запроса. При POST - другое дело, параметры постятся в теле запроса, но зато ты не можешь опубликовать ссылку на результат запроса. Вообще, это основы HTTP, который бы стоило подучить (справедливости ради, нормальных уроков по теме я не видел, а свой все руки не доходят написать).
>>996051
В модели.
> Чтобы посчитать сколько файлов в текущей папке нужно сначала определить есть ли текущая папка вообще (на случай если файл загружается впервые), затем посчитать сколько в этой папке файлов, и определить есть ли там файл с таким именем. Получается довольно большой блок условий.
Потому нужно решать задачу по-другому. Ну например, чтобы гарантировать уникальность имен, можно приписывать к ним id файла, который гарантированно уникален. Или генерировать GUID/UUID ( https://ru.wikipedia.org/wiki/GUID https://ru.wikipedia.org/wiki/UUID ). Что касается распределения по папкам, если известен Id, можно вычислять папку из него, если нет, можно делать папки по дате/времени исходя из оценки, сколько у нас примерно загружается файлов за единицу времени.
>>996043
> http://ideone.com/sPOexI Доллары в рубли
Верно
> http://ideone.com/tMu8IN Кубики
Тут еще возможна ничья, когда нет даблов, но число очков одинаковое - это не проверяется.
> http://ideone.com/P3xI5r Миллион в банке
Верно, хотя я бы использовал += для увеличения $resultSum.
> http://ideone.com/xutDDU Айфон
Интересно, что этой задаче уже несколько лет, а айфоны все еще не исчезли, и не подешевели даже, и текст не требуется переписывать.
Слишком большое решение, например формула $creditBalance x $percent + $servicePayment встречается аж 3 раза, попробуй избавиться от повторов.
> http://ideone.com/6WlyG3 Средняя оценка
Верно
> http://ideone.com/INkXnO Рост анона
Верно, но я бы использовал тут оператор ++
> http://ideone.com/3YTUk6 Ответ на любой вопрос
Тут можно обойтись без array_flip, просто взяв из массива значение по полученному индексу.
> http://ideone.com/GMEMJi Шифровка
Ок, все верно.
>>995949
Кстати, тут еще много тем, которые можно обсудить поподробнее, да даже эффективный выбор случайного значения из БД - уже сама по себе отдельная тема.
> Чтобы посчитать сколько файлов в текущей папке нужно сначала определить есть ли текущая папка вообще (на случай если файл загружается впервые), затем посчитать сколько в этой папке файлов, и определить есть ли там файл с таким именем. Получается довольно большой блок условий.
Потому нужно решать задачу по-другому. Ну например, чтобы гарантировать уникальность имен, можно приписывать к ним id файла, который гарантированно уникален. Или генерировать GUID/UUID ( https://ru.wikipedia.org/wiki/GUID https://ru.wikipedia.org/wiki/UUID ). Что касается распределения по папкам, если известен Id, можно вычислять папку из него, если нет, можно делать папки по дате/времени исходя из оценки, сколько у нас примерно загружается файлов за единицу времени.
>>996043
> http://ideone.com/sPOexI Доллары в рубли
Верно
> http://ideone.com/tMu8IN Кубики
Тут еще возможна ничья, когда нет даблов, но число очков одинаковое - это не проверяется.
> http://ideone.com/P3xI5r Миллион в банке
Верно, хотя я бы использовал += для увеличения $resultSum.
> http://ideone.com/xutDDU Айфон
Интересно, что этой задаче уже несколько лет, а айфоны все еще не исчезли, и не подешевели даже, и текст не требуется переписывать.
Слишком большое решение, например формула $creditBalance x $percent + $servicePayment встречается аж 3 раза, попробуй избавиться от повторов.
> http://ideone.com/6WlyG3 Средняя оценка
Верно
> http://ideone.com/INkXnO Рост анона
Верно, но я бы использовал тут оператор ++
> http://ideone.com/3YTUk6 Ответ на любой вопрос
Тут можно обойтись без array_flip, просто взяв из массива значение по полученному индексу.
> http://ideone.com/GMEMJi Шифровка
Ок, все верно.
>>995949
Кстати, тут еще много тем, которые можно обсудить поподробнее, да даже эффективный выбор случайного значения из БД - уже сама по себе отдельная тема.
>>988782
Не блокируется действие по умолчанию при клике правой кнопкой и появляется меню. Но выглядит симпатично.
> Модули node и commonjs имеют одинаковый синтаксис? Есть ли экспорт по умолчанию в commonjs: module.export = MyClass или это только фишка node модулей?
Не совсем одинаковый, есть список различий на англ: https://www.quora.com/How-is-the-Node-js-module-system-different-than-CommonJS
> Как я понял, webpack не умеет грузить напрямую, зато есть режим watch, который обновляет сборку в режиме реального времени, и несколько видов карты файлов.
Вот эта идея что-то постоянно пересобирать при разработке - на мой взгляд, она только замедляет работу. Склейка в один бандл была придумана как ответ на недостатки HTML и HTTP/1. HTML требует останавливать парсинг HTML-кода до загрузки и выполнения скрипта, а HTTP/1 требует создавать новое TCP-соединение на каждый запрос, при большом пинге значительная часть времени уходит на обмен пакетами для установки соединения + установку шифрования в случае HTTPS. То есть если пинг 100мс, для установки TCP соединения надо 3 обмена пакетами + еще пару для установки SSL, получается что мы тратим 250мс на инициализацию соединения, по которому может быть за 10 мс мы скачаем один скрипт. Склейка позволяет частично победить эту проблему. Но она создает другие, например требует при разработке использовать маппинг (который должен поддерживаться отладчиком) для корректного отображения скриптов в исходном виде. Выглядит как борьба с проблемами, которые мы сами же себе и создаем.
Но со временем эти проблемы уходят в прошлое. Протокол HTTP/2 позволяет по одному соединению с хорошей скоростью выкачивать параллельно много файлов без задержек. И новые ES6 Modules решают проблему блокировки парсинга HTML и предоставляют удобный синтаксис. Поскольку они будут частью JS и будут встраиваться в браузеры, очевидно что это самый перспективный стандарт. Думаю, и нода на них перейдет когда-нибудь.
Описание на англ: http://2ality.com/2014/09/es6-modules-final.html
Нужна ли склейка на dev сервере? Даже на HTTP/1 проблем с пингом тут нет, HTTPS тоже нет, пересборка (на мой взгляд) лишь приводит к лишним затратам времени. Более того, функция watch в зависимости от версии ОС и ноды может потреблять процессор (можешь проверить). Мне кажется, что удобнее не создавать самому себе проблемы, а загружать исходные версии файлов.
Лучше всего было бы на dev использовать ES6 modules напрямую и новый браузер, а для продакшена, где есть много старых браузеров, не поддерживающих их и HTTP/2, делать склеенную версию. Но! http://caniuse.com/#search=es6 module показывает что пока ES6 кроме Сафари (а также новейшего Хрома, Edge и ФФ с включенным флагом конфига) никто не поддерживает :(
Судя по https://webpack.js.org/concepts/modules/ webpack2 понимает ES6 модули.
Соответственно, мне кажется, перспективно делать так:
- модули пишутся в синтаксисе ES6 Module
- разработчик с поддержкой ES6 Module просто грузит их нативно без помощи webpack
- на продакшен собирается бандл в старом синтаксисе через webpack. Наверно, ES6 код придется транспилировать в ES5 (а лучше вообще в ES3, но не уверен, что это возможно).
- разработчик без ES6 мог бы использовать загрузчик или polyfill, который загружает модули например через аякс запросы + eval. Вроде https://github.com/ModuleLoader/browser-es-module-loader . Но я не уверен, что это будет нормально работать, потому ему придется наверно использовать webpack.
Такие сложности нужны из-за того, что технология очень новая и мало где поддерживается.
По коду, я тут вижу сложное место:
> https://github.com/enotocode/minesweeper.mvc/blob/master/app/MinesweeperGame.js#L131
> MinesweeperGame.prototype.getMinesQuantity = function(x, y) {
> return this._cells[x][y].surroundingMines;
А где гарантия что к моменту вызова getMinesQuantity() поля surroundingMines заполнено? Не лучше ли было бы вычислять количество при первом вызове метода?
Также, у тебя там число 12 повторяется в коде, надо было сделать его свойством.
> А как делить файлы по папкам, View/Controller/Other ?
MVC не значит что должно быть ровно 3 папки. В данном случае, можно например сделать такую структуру, группируя файлы по типу:
- View
- Controller
- Event
- Model (Cell, MinesweeperGame)
- EventDispatcher.js
- ViewHelper.js
Есть также другой вариант, можно группировать классы, которые используются вместе:
- Browser
- Console
- Event
- Modal
- ...
Ну вообще, 15 файлов еще терпимо, но в более сложном приложении папки понадобятся.
> Вопрос про ModalView
Тут можно избавиться от связи между попапом и моделью игры вообще. Пусть ModalController при нажатии кнопки не перезапускает игру, а просто генерирует событие вроде BUTTON_CLICK. То есть любой желающий может создать ModalController, дать ему текст попапа, подписи для кнопок, подписаться на его событие и открыть попап. Любой попап с любым текстом, не обязательно связанный с перезапуском игры.
Соответственно, game.restart() тогда надо вызывать в BrowserController. И там же, кстати, надо закрывать попап если мы перезапустили игру из консоли.
Также, у меня ощущение что тогда ModalContoller можно будет вообще выкинуть и работать с ModalView напрямую. То есть создаем ModalView, даем ему текст, подписываемся на событие.
Вот примерно так:
BrowserViewController.prototype.createModal = function() {
var modal = new ModalPopupView(domElement);
modal.setText('....');
modal.setButtons(....);
modal.subscribe(EVENT_BUTTON_CLICK, function () {
that._game.restart();
});
modal.show();
// Если игра перезапущена не через попап
this._game.subscribe(EVENT_RESTART, function () {
if (modal.isVisible()) {
modal.destroy();
}
});
}
Надеюсь, суть понятна. Мы полностью отвязываем попап от игры.
В моем коде кстати есть еще маленькая проблемка, утечка памяти. Мы каждый раз создаем новый объект modal, и добавляем в _game ссылку на него через новую подписку. Число подписок только растет со временем. Даже если попап давно закрыт, обработчик события RESTART удерживает ссылку на этот старый попап. Надо отписываться от события при закрытии попапа. Либо же надо подписываться на событие EVENT_RESTART где-то в другом месте и один раз.
В твоем коде эта проблема по моему тоже есть - subscribe вызывается при каждом открытии попапа но подписки никогда не удаляются.
> вопрос про вывод поля в консоли
> И нужно будет перерисовывать поле каждый раз, при открытии каждой клетки, но за один ход могут открыться сразу несколько соседних, если рядом с ними нет мин. Сейчас так выглядит вывод поля в консоли браузера.
Это потому что у тебя нет группировки событий (произошедших в течение выполнения одной функции). Я подумал, наверно проще всего было бы сделать аггрегацию событий на уровне EventDispacther:
this._model.eventDispatcher.subscribeAggregate(MinesweeperGame.EVENT_CELL_OPENED, function (events ) { // массив накопленных событий
сгенерировать и вывести новое поле;
});
Это можно сделать например через трюк с нулевым таймаутом. То есть мы кладем событие в массив и ставим нулевой таймаут, если он еще не поставлен. По таймауту вызываем обработчик, и он вызвается с массивом накопленных событий.
Агрегация событий часто нужна, иначе на каждый чих все будет перерисовываться.
> Т.к. я договорился что внутреннее хранилище с ячейкими не покинет модели, мне нужно сделать метод получения данных о всех ячейках, т.е. создать новый формат для передачи данных или клонировать массив со всеми классами внутри. А потом отрисовывать его?
Можно в цикле вызывать существующие методы для каждой ячейки. Просто ты поддерживаешь по сути вторую копию модели и синхронизируешь изменения, это сложно и легко допустить ошибку.
Хотя в плане производительности, может быть, поддерживать копию поля выгоднее. Только лучше сделать эту копию массивом строк или массиво символов и заменять символ лучше не через пересоздание строки, а через string[x] = N;
> 2. Можно добавить два статуса для метода модели openCell(), при запуске метода статус изменяется на OPENING, в самом конце выполнения статус на - WAITING. Функция входит в рекурсию до изменения статуса на WAITING, а в режиме рекурсии не меняет совсем. View должна иметь прямой доступ к модели или сделать этот статус свойством события открытия каждой клетки.
Это сильно усложнит код.
Вообще, мне кажется, стоит потихоньку заканчивать с этой задачей, и двигаться дальше. Мы и так на нее много времени потратили, а это всего лишь простая игра, и она не позволит нам изучить все аспекты создания SPA приложений.
Ну например, можно взяться за задачу на SPA из ОП поста. Хотя она сложная, может перед ней стоит сделать что-нибудь попроще, например, терминал кассира для оформления заказов в фастфуде с отправкой заказов на сервер, или терминал сотрудника ресепшена в отеле (забыл, как эта профессия называется) или простой мессенджер. Тут тебе пригодится и MVC, и что-нибудь из Angular/Knockout/React.
Но задачу на SPA хорошо бы сделать. Мало кто сейчас такие штуки умеет делать.
>>988782
Не блокируется действие по умолчанию при клике правой кнопкой и появляется меню. Но выглядит симпатично.
> Модули node и commonjs имеют одинаковый синтаксис? Есть ли экспорт по умолчанию в commonjs: module.export = MyClass или это только фишка node модулей?
Не совсем одинаковый, есть список различий на англ: https://www.quora.com/How-is-the-Node-js-module-system-different-than-CommonJS
> Как я понял, webpack не умеет грузить напрямую, зато есть режим watch, который обновляет сборку в режиме реального времени, и несколько видов карты файлов.
Вот эта идея что-то постоянно пересобирать при разработке - на мой взгляд, она только замедляет работу. Склейка в один бандл была придумана как ответ на недостатки HTML и HTTP/1. HTML требует останавливать парсинг HTML-кода до загрузки и выполнения скрипта, а HTTP/1 требует создавать новое TCP-соединение на каждый запрос, при большом пинге значительная часть времени уходит на обмен пакетами для установки соединения + установку шифрования в случае HTTPS. То есть если пинг 100мс, для установки TCP соединения надо 3 обмена пакетами + еще пару для установки SSL, получается что мы тратим 250мс на инициализацию соединения, по которому может быть за 10 мс мы скачаем один скрипт. Склейка позволяет частично победить эту проблему. Но она создает другие, например требует при разработке использовать маппинг (который должен поддерживаться отладчиком) для корректного отображения скриптов в исходном виде. Выглядит как борьба с проблемами, которые мы сами же себе и создаем.
Но со временем эти проблемы уходят в прошлое. Протокол HTTP/2 позволяет по одному соединению с хорошей скоростью выкачивать параллельно много файлов без задержек. И новые ES6 Modules решают проблему блокировки парсинга HTML и предоставляют удобный синтаксис. Поскольку они будут частью JS и будут встраиваться в браузеры, очевидно что это самый перспективный стандарт. Думаю, и нода на них перейдет когда-нибудь.
Описание на англ: http://2ality.com/2014/09/es6-modules-final.html
Нужна ли склейка на dev сервере? Даже на HTTP/1 проблем с пингом тут нет, HTTPS тоже нет, пересборка (на мой взгляд) лишь приводит к лишним затратам времени. Более того, функция watch в зависимости от версии ОС и ноды может потреблять процессор (можешь проверить). Мне кажется, что удобнее не создавать самому себе проблемы, а загружать исходные версии файлов.
Лучше всего было бы на dev использовать ES6 modules напрямую и новый браузер, а для продакшена, где есть много старых браузеров, не поддерживающих их и HTTP/2, делать склеенную версию. Но! http://caniuse.com/#search=es6 module показывает что пока ES6 кроме Сафари (а также новейшего Хрома, Edge и ФФ с включенным флагом конфига) никто не поддерживает :(
Судя по https://webpack.js.org/concepts/modules/ webpack2 понимает ES6 модули.
Соответственно, мне кажется, перспективно делать так:
- модули пишутся в синтаксисе ES6 Module
- разработчик с поддержкой ES6 Module просто грузит их нативно без помощи webpack
- на продакшен собирается бандл в старом синтаксисе через webpack. Наверно, ES6 код придется транспилировать в ES5 (а лучше вообще в ES3, но не уверен, что это возможно).
- разработчик без ES6 мог бы использовать загрузчик или polyfill, который загружает модули например через аякс запросы + eval. Вроде https://github.com/ModuleLoader/browser-es-module-loader . Но я не уверен, что это будет нормально работать, потому ему придется наверно использовать webpack.
Такие сложности нужны из-за того, что технология очень новая и мало где поддерживается.
По коду, я тут вижу сложное место:
> https://github.com/enotocode/minesweeper.mvc/blob/master/app/MinesweeperGame.js#L131
> MinesweeperGame.prototype.getMinesQuantity = function(x, y) {
> return this._cells[x][y].surroundingMines;
А где гарантия что к моменту вызова getMinesQuantity() поля surroundingMines заполнено? Не лучше ли было бы вычислять количество при первом вызове метода?
Также, у тебя там число 12 повторяется в коде, надо было сделать его свойством.
> А как делить файлы по папкам, View/Controller/Other ?
MVC не значит что должно быть ровно 3 папки. В данном случае, можно например сделать такую структуру, группируя файлы по типу:
- View
- Controller
- Event
- Model (Cell, MinesweeperGame)
- EventDispatcher.js
- ViewHelper.js
Есть также другой вариант, можно группировать классы, которые используются вместе:
- Browser
- Console
- Event
- Modal
- ...
Ну вообще, 15 файлов еще терпимо, но в более сложном приложении папки понадобятся.
> Вопрос про ModalView
Тут можно избавиться от связи между попапом и моделью игры вообще. Пусть ModalController при нажатии кнопки не перезапускает игру, а просто генерирует событие вроде BUTTON_CLICK. То есть любой желающий может создать ModalController, дать ему текст попапа, подписи для кнопок, подписаться на его событие и открыть попап. Любой попап с любым текстом, не обязательно связанный с перезапуском игры.
Соответственно, game.restart() тогда надо вызывать в BrowserController. И там же, кстати, надо закрывать попап если мы перезапустили игру из консоли.
Также, у меня ощущение что тогда ModalContoller можно будет вообще выкинуть и работать с ModalView напрямую. То есть создаем ModalView, даем ему текст, подписываемся на событие.
Вот примерно так:
BrowserViewController.prototype.createModal = function() {
var modal = new ModalPopupView(domElement);
modal.setText('....');
modal.setButtons(....);
modal.subscribe(EVENT_BUTTON_CLICK, function () {
that._game.restart();
});
modal.show();
// Если игра перезапущена не через попап
this._game.subscribe(EVENT_RESTART, function () {
if (modal.isVisible()) {
modal.destroy();
}
});
}
Надеюсь, суть понятна. Мы полностью отвязываем попап от игры.
В моем коде кстати есть еще маленькая проблемка, утечка памяти. Мы каждый раз создаем новый объект modal, и добавляем в _game ссылку на него через новую подписку. Число подписок только растет со временем. Даже если попап давно закрыт, обработчик события RESTART удерживает ссылку на этот старый попап. Надо отписываться от события при закрытии попапа. Либо же надо подписываться на событие EVENT_RESTART где-то в другом месте и один раз.
В твоем коде эта проблема по моему тоже есть - subscribe вызывается при каждом открытии попапа но подписки никогда не удаляются.
> вопрос про вывод поля в консоли
> И нужно будет перерисовывать поле каждый раз, при открытии каждой клетки, но за один ход могут открыться сразу несколько соседних, если рядом с ними нет мин. Сейчас так выглядит вывод поля в консоли браузера.
Это потому что у тебя нет группировки событий (произошедших в течение выполнения одной функции). Я подумал, наверно проще всего было бы сделать аггрегацию событий на уровне EventDispacther:
this._model.eventDispatcher.subscribeAggregate(MinesweeperGame.EVENT_CELL_OPENED, function (events ) { // массив накопленных событий
сгенерировать и вывести новое поле;
});
Это можно сделать например через трюк с нулевым таймаутом. То есть мы кладем событие в массив и ставим нулевой таймаут, если он еще не поставлен. По таймауту вызываем обработчик, и он вызвается с массивом накопленных событий.
Агрегация событий часто нужна, иначе на каждый чих все будет перерисовываться.
> Т.к. я договорился что внутреннее хранилище с ячейкими не покинет модели, мне нужно сделать метод получения данных о всех ячейках, т.е. создать новый формат для передачи данных или клонировать массив со всеми классами внутри. А потом отрисовывать его?
Можно в цикле вызывать существующие методы для каждой ячейки. Просто ты поддерживаешь по сути вторую копию модели и синхронизируешь изменения, это сложно и легко допустить ошибку.
Хотя в плане производительности, может быть, поддерживать копию поля выгоднее. Только лучше сделать эту копию массивом строк или массиво символов и заменять символ лучше не через пересоздание строки, а через string[x] = N;
> 2. Можно добавить два статуса для метода модели openCell(), при запуске метода статус изменяется на OPENING, в самом конце выполнения статус на - WAITING. Функция входит в рекурсию до изменения статуса на WAITING, а в режиме рекурсии не меняет совсем. View должна иметь прямой доступ к модели или сделать этот статус свойством события открытия каждой клетки.
Это сильно усложнит код.
Вообще, мне кажется, стоит потихоньку заканчивать с этой задачей, и двигаться дальше. Мы и так на нее много времени потратили, а это всего лишь простая игра, и она не позволит нам изучить все аспекты создания SPA приложений.
Ну например, можно взяться за задачу на SPA из ОП поста. Хотя она сложная, может перед ней стоит сделать что-нибудь попроще, например, терминал кассира для оформления заказов в фастфуде с отправкой заказов на сервер, или терминал сотрудника ресепшена в отеле (забыл, как эта профессия называется) или простой мессенджер. Тут тебе пригодится и MVC, и что-нибудь из Angular/Knockout/React.
Но задачу на SPA хорошо бы сделать. Мало кто сейчас такие штуки умеет делать.
Никак, если только ты не делал бекапы.
>>993659
Разве есть сортировка со сложностью O(log(N))? Почему никто не обратил внимания, а еще php тред называется...
>>993650
gettype() либо var_dump() если надо вывести тип переменной и содержимое на экран.
>>993623
echo выводит только строки, все, что не строка, он приводит к строке. Массив он вывести вообще не может. А var_dump показывает тип переменной и данные, как есть. Он нужен для отладки программы.
>>993559
А почему ты не хочешь использовать SQL? Он специально был придуман для работы с данными и вряд ли код на PHP с кучей кавычек и скобочек его превзойдет.
>>993502
Может быть, да. зависит от объема данных, если их очень много, то может надо придумывать что-то более оптимальное. У MySQL есть еще вполне заметное ограничение на число вставок в секунду (из-за требований к надежности хранения данных), если у тебя тысячи сообщений в секунду, то конечно придется импровизировать.
Может есть какие-то более удачные хранилища, но я сейчас не могу их назвать. Возможно, что все возможности SQL для хранения сообщений и не нужны. Все же MySQL это хранилище общего назначения, не заточенное именно под хранение сообщений.
Я знаю, что вконтакте использовал написанное на Си хранилище, а что исплоьзуют другие сайты ты можешь поискать тут: https://www.insight-it.ru/highload/
Никак, если только ты не делал бекапы.
>>993659
Разве есть сортировка со сложностью O(log(N))? Почему никто не обратил внимания, а еще php тред называется...
>>993650
gettype() либо var_dump() если надо вывести тип переменной и содержимое на экран.
>>993623
echo выводит только строки, все, что не строка, он приводит к строке. Массив он вывести вообще не может. А var_dump показывает тип переменной и данные, как есть. Он нужен для отладки программы.
>>993559
А почему ты не хочешь использовать SQL? Он специально был придуман для работы с данными и вряд ли код на PHP с кучей кавычек и скобочек его превзойдет.
>>993502
Может быть, да. зависит от объема данных, если их очень много, то может надо придумывать что-то более оптимальное. У MySQL есть еще вполне заметное ограничение на число вставок в секунду (из-за требований к надежности хранения данных), если у тебя тысячи сообщений в секунду, то конечно придется импровизировать.
Может есть какие-то более удачные хранилища, но я сейчас не могу их назвать. Возможно, что все возможности SQL для хранения сообщений и не нужны. Все же MySQL это хранилище общего назначения, не заточенное именно под хранение сообщений.
Я знаю, что вконтакте использовал написанное на Си хранилище, а что исплоьзуют другие сайты ты можешь поискать тут: https://www.insight-it.ru/highload/
А ты комментарии в задаче про студентов из ОП поста читал?
По поводу Registry, глянь этот урок, если не читал https://github.com/codedokode/pasta/blob/master/arch/di.md
По работе с БД - глянь это, если не читал https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
По исключениям - посмотри этот урок, если еще не читал https://github.com/codedokode/pasta/blob/master/php/exceptions.md
Дамп БД лучше поместить в проект в формате sql. Архивировать не надо.
Описание структуры проекта можно поместить в файл structure.md и поставить на него относительную ссылку в README.
У тебя много библиотек в папке vendor, но почему-то их нет в composer.json. В репозитории как раз папка vendor не нужна, в нем по возможности должен быть только твой код. Идея в том, что тот, кто скачал твой код, запустит композер и он установит нужные библиотеки.
Для безопасности желательно сделать публичную папку, а весь остальной код разместить за ее пределами, чтобы он был недоступен веб-серверу.
По работе с формами есть урок https://github.com/codedokode/pasta/blob/master/forms.md
Позже может быть еще напишу комментарии.
> Это неправильный код. $char это строка, а не булевское значение (true/false). Это если и работает, то за счет каких-то странностей преобразования строк в булевские значения при сравнении. Попробуй сам прочитать: 'если i-й символ в строке равен TRUE' - как такое может быть?
Взял такое отсюда - https://habrahabr.ru/post/113253/ в мануале пхп так тоже делают http://php.net/manual/en/language.types.string.php#language.types.string.casting или это что-то другое?
Мой код с трудом расширяется и почти не реюзабелен, поэтому не могу пока им гордится.
Читал Мэтт Зандстра (не полностью, шаблоны мне пока не требуются), Совершенный Код Макконнела (он заразил меня перфекционизмом, от которого теперь страдаю, потому что вижу, что код не такой, какой должен быть, а сделать правильно не умею).
Мне хочется сделать как в фреймворках, наверное, мне стоит сделать что-то на микрофрмврке как в оппосте.
>>997294
> Не открывается.
Точно? Я проверил с другого браузера и телефона, открывается. Хостинг бесплатный, поэтому очень часто бывают ошибки 500, лучшего хостинга с php7 я пока найти не смог (если найдёте, киньте). Просто рефрешни несколько раз страницу.
>>997323
> А ты комментарии в задаче про студентов из ОП поста читал?
Читал, но не все со стопроцентной эффективностью осмыслил.
> По работе с БД
Читал, на основе её и придумал Student|PasswordMapper'ы.
> Описание структуры проекта можно поместить в файл structure.md
Маркдаун не переваривает табы и игнорирует пробельные отступы.
> У тебя много библиотек в папке vendor, но почему-то их нет в composer.json.
https://packagist.org/packages/phpunit/phpunit requires
Оставшиеся нужны были одной библиотеке, которую я затем выпилил ручками, т.к. не разобрался, как в phpStorm удалять что-то из композера.
> В репозитории как раз папка vendor не нужна, в нем по возможности должен быть только твой код. Идея в том, что тот, кто скачал твой код, запустит композер и он установит нужные библиотеки.
Понятно. Пересобрал у себя vendor, удалил папку из гитхаба (это, кстати, можно сделать только через git shell)
> По работе с формами
Читал, старался так и делать. Алсоу, предложенный там вариант с strval не работает с массивами, потому что строка конвертируется в Array и выбрасывается Notice типа:
Notice: Array to string conversion in .php on line 4
string(5) "Array"
Поэтому способа обезопасить себя от подстановки массива одной функцией в PHP нет, нужен is_array.
> По поводу Registry
Займусь этим сейчас.
>Для безопасности желательно сделать публичную папку, а весь остальной код разместить за ее пределами, чтобы он был недоступен веб-серверу.
Сделаю так, когда разберусь с другими проблемами структуры проекта. Для контроля доступности использую .htaccess, можешь попробовать вытащить из сайта волнительный файл типа xml.
> Позже может быть еще напишу комментарии.
Смотрел сайт? Попробуй потыкать кнопочки, напиши впечатление.
Мой код с трудом расширяется и почти не реюзабелен, поэтому не могу пока им гордится.
Читал Мэтт Зандстра (не полностью, шаблоны мне пока не требуются), Совершенный Код Макконнела (он заразил меня перфекционизмом, от которого теперь страдаю, потому что вижу, что код не такой, какой должен быть, а сделать правильно не умею).
Мне хочется сделать как в фреймворках, наверное, мне стоит сделать что-то на микрофрмврке как в оппосте.
>>997294
> Не открывается.
Точно? Я проверил с другого браузера и телефона, открывается. Хостинг бесплатный, поэтому очень часто бывают ошибки 500, лучшего хостинга с php7 я пока найти не смог (если найдёте, киньте). Просто рефрешни несколько раз страницу.
>>997323
> А ты комментарии в задаче про студентов из ОП поста читал?
Читал, но не все со стопроцентной эффективностью осмыслил.
> По работе с БД
Читал, на основе её и придумал Student|PasswordMapper'ы.
> Описание структуры проекта можно поместить в файл structure.md
Маркдаун не переваривает табы и игнорирует пробельные отступы.
> У тебя много библиотек в папке vendor, но почему-то их нет в composer.json.
https://packagist.org/packages/phpunit/phpunit requires
Оставшиеся нужны были одной библиотеке, которую я затем выпилил ручками, т.к. не разобрался, как в phpStorm удалять что-то из композера.
> В репозитории как раз папка vendor не нужна, в нем по возможности должен быть только твой код. Идея в том, что тот, кто скачал твой код, запустит композер и он установит нужные библиотеки.
Понятно. Пересобрал у себя vendor, удалил папку из гитхаба (это, кстати, можно сделать только через git shell)
> По работе с формами
Читал, старался так и делать. Алсоу, предложенный там вариант с strval не работает с массивами, потому что строка конвертируется в Array и выбрасывается Notice типа:
Notice: Array to string conversion in .php on line 4
string(5) "Array"
Поэтому способа обезопасить себя от подстановки массива одной функцией в PHP нет, нужен is_array.
> По поводу Registry
Займусь этим сейчас.
>Для безопасности желательно сделать публичную папку, а весь остальной код разместить за ее пределами, чтобы он был недоступен веб-серверу.
Сделаю так, когда разберусь с другими проблемами структуры проекта. Для контроля доступности использую .htaccess, можешь попробовать вытащить из сайта волнительный файл типа xml.
> Позже может быть еще напишу комментарии.
Смотрел сайт? Попробуй потыкать кнопочки, напиши впечатление.
Видимо, разрешение экрана маленькое, при том что размер шрифтов не менялся. Попробуй изменить отдалить в браузере (в хроме контрол + колесико мыши). Так, конечно, плохо, но хотя бы заценишь кнопочки. Не учился адаптивной верстке, тестировал на 1600-900.
>Я бы не советовал делать страницы ошибок через контроллеры. Ведь ошибка может произойти где-то в базовом классе контроллера или на момент ошибки какие-то компоненты могут быть недоступны. Лучше сделать страницу ошибки как можно проще, без лишних зависимостей, без проверок авторизации и прочего.
>Название для исключения тоже неправильное, хотя бы с точки зрения грамматики, my пишется перед exception.
>Название метода тоже неправильное. Ты его назвал "getErrorPage" но он ничего не возвращает - должно быть printErrorPage().
Пофиксил.
Ну и в твоем случае нужно указать конкретно, что это за исключение (например AssertionFailedException). Также, обрати внимание, что в PHP есть готовые исключения: http://php.net/manual/ru/spl.exceptions.php
Глянул, потом углублюсь. У меня исключения только-только стали укладываться в голове.
Сейчас по другому попробовал, понятно что говно, но в принципе, решение то жизнеспособное? Получше хоть стало?
https://github.com/grigoryMovchan/AphorismCMS/blob/master/index.php
https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Core/ErrorHandler.php
Прочитал https://github.com/codedokode/pasta/tree/master/security
Но плохо понял как обмазать проект безопасностью. Что бы защититься от уязвимости sql - нужно санитайзить переменные непосредственно перед тем как он попадет в базу? Если например нет возможности удостовериться, что селекты и инсерты выполняются через плейсхолдеры где-то там в ядре фремворка, на котором написан проект, правильно?
Далее что касается js уязвимостей. То это уже во вьюхе при выводе инфы от юзеров в шаблон нужно обмазывать? Что бы потенциальный js код не поставился во вьюху и не выполнился вредоносно?
Что по поводу аплоада файлов, ни слова не сказано как защититься от загрузки pidor.php в папку с аватарками и дальнейшим доступом ко всему коду / в админку проекта.
>>997323
> По поводу Registry, глянь этот урок, если не читал
Прочитал, написал свою реализацию DIContainer: https://pastebin.com/qDiPiNYW (алсо, какое пастохранилище использовать лучше пастбина?)
Сейчас начну пробовать избавиться от Реестра, и заранее видно затруднение: описание фабрик, как в примере:
> // Описываем как создать объект работы с БД, зависящий от PDO
> $container['userDataGateway'] = function ($container) {
> return new UserDataGateway($container['pdo']);
> };
всех нужных объектов и данных приведёт к большому куску кода, которому абсолютно нечего делать в index.php и тому подобных скриптах. Его нужно упаковать либо в отдельный скрипт (это тупо), либо придумать класс типа app или controller, который органично будет все эти фабрики заполнять и регистрировать. Думаю об этом, но пока не знаю, как сделать.
Я виндоблядь.
пхп+энжинкс+мускл+что еще угодно, похуй.
На локалке есть все это, но использую редко, всю разработку веду сразу на сервере (убунту или дебиан). Там все точно тоже самое стоит, только нормально работает. Никаких пма и подобного, только консоль.
Вообще посоветуйте, что лучше всего использовать для полноценного чата с лайками, модерированием и общим сохранением сообщений в базе.
>>997702
Ставь всё по отдельности, это не сложно. У меня PHP7 стоит на локальном, которого ещё долго не будет в таких вот сборках, типа WAMPP. MariaDB - там так-то то же самое, но зачем.
>Опрос: на какой системе вы программируете, как вы поставили php+apache+БД+ ... ?
Сижу в винде, сервер там же на Virtualbox + Vagrant. Не ебу как это работает. Запускаю одной командой виртуалку с убунтой без гуя, она там где-то крутится, кидаю скрипты в папочку в винде и в браузере их запускаю, доступ к консоли сервака через SSH. Только phpmyadmin поставил.
>кросс-ОС-овской разработки
Хуй знает что это, не сталкивался с проблемами из-за ОС.
Наверное, луче всего было бы перекатится на убунту полностью. Но мне у винды интерфейс больше нравится, он более аккуратный и миниатюрный что-ли, а скорее линукс в винде из коробки будет без всяких виртуалок. В удивительное время живем.
>Вообще посоветуйте, что лучше всего использовать для полноценного чата с лайками, модерированием и общим сохранением сообщений в базе.
Для портфолио пилишь?
О, точно, не сказал, для чего нужно.
На своём сайте хочу сделать просто чат.
Если это будет готовое решение, то тоже нормально.
Но мне нужна сложнота и неочевидность: чат и окно для лучших сообщений - которым больше всего поставили лайков.
Чатятся, ставят лайки - если 10% от чатящихся поставили лайки сообщению - оно переносится в то окошко.
Вот думаю погрузиться в ВебСокет и запилить сие.
Пока что натянул вёрстку на вордпресс, вёрстка сделана тоже мной из ПСД ОПа, правда она не адаптивная, но я исправлю это. Адрес сайта на прикреплённой пикче, извиняюсь за неудобство, но при попытке вставить ссылку в пост двач пишет что присутсвует слов из спам листа. Проверить натяжку на саму вордпресс можно через админку, доступ:
Логин - Admin
Пароль - admin
Контент сделал через записи, также есть страница настроек темы, зайти в неё можно по адресу Внешний вид->настройки темы
Подскажет тут кто-то сервис, который позволяет выводить средства пользователям? Любая информация, может подкинете мыслю, где искать.
Интересует такая залупа, как Робокасса, только в обратную сторону -- деньги необходимо выводить именно пользователю с сайта.
>>997707
>>997712
>>997729
Странно что в треде столько виндовых "вебмастеров" и при этом никто не знает про https://ospanel.io/
Всем ньюфагам рекомендую. Несколько лет назад когда вкатился и 1 раз установил всё ручками "пушто так надо и тру", быстро понял прелесть денверов и всяких изипхп, но денвер давно мертв, а тут всё удобненько и актуально.
> энжинкс
Почему никсы, а не апач? В никсах не разбирался, читал лишь вкратце, что они попроще апача и победнее функциями, для статических сайтов.
> только консоль.
Дело привычки, или другая причина не использовать гуи?
>>997783
Видел эту штуку, но там много всего лишнего для моего уровня, + она только для виндовс, а хотелось бы папочку, которую просто копируешь из винды в линукс с минимумом переделок.
>>997786
> нахуй удалить лишнюю папку из репозитория.
Я знаю как.
> Не надо ничего советовать
Ладно.
У меня винда выступает в роли того, на чем я сам сижу и где ИДЕ запускаю. Существенной разницы нет, на работе с мака хваленого сидел, не принципиально, все одно и то же. Всего-лишь дело привычки. Если в нерабочее время я использую винду, то мне и для работы ее удобнее использовать, чтобы не переключаться лишний раз.
Мне, как ни странно, гораздо проще руками все развернуть. На стандартный набор минут 10 отсилы уходит (энжинкс, пхп, перкона), под убунтой проще всего вообще в 1 команду все обернуть, собственно зачем на фоне этого какие-то готовые сборки? Хуево самому накатывать редис или необычную бд, и то не всегда, но мне этот процесс интересен, так что вполне доволен всем. Можно вагрантом пользоваться изи, но по причине наличия 3х тестовых серверов не имею потребности в нем.
>>997800
>Почему никсы, а не апач?
>Дело привычки, или другая причина не использовать гуи?
Вкусовщина и то и другое.
>для статических сайтов
Энжинкс уже давно через пхпфпм отлично работает с динамическим контентом.
>для картинок, выводить информацию и превьюшку
>для медиафайлов (аудио/видео), выводить информацию (ее можно получить с помощью библиотеки вроде gitId3, не руками же файлы расковыривать)
Какую информацию обычно нужно выводить?
Для картинок, наверно, достаточно будет разрешение и её тип. А для видео и аудио что нужно?
https://github.com/Merkalov/Students
Детище моё.
Залил на хостинг
http://students-list.ru.host1590257.serv66.hostland.pro/
Что бы не регаться используйте
Логин/пасс: totarin@r.ru
За ООП не поясню. За МВЦ раскидаю.
Вместо PDO и mysqli использовал фреймворк Medoo(который на PDO работает).
При заливке на хостиг сразу вылезли ошибки моей молодости(абсолютные/относительные пути, где-то вообще написан сам сайт(Students\list), вместо пути, за это уже понял не ругай.)
Куки на 10 лет + привязка к IP-адресу.
Версия php 5.5 - залил на хостинг, где 5.4 - сразу отвалилась авторизация с чудесным методом password_verify();
Код отформатировал встроенный в phpShtorm форматировщий(кроме Helper.php).
Собирался ещё допилить проверку полей через js, но руки не дошли. А так довольно занимательно в выходные проводить 10ч к ряду за написанием кода, забывая поесть.
Счётчик накрутил 54+ часа работы над проектом,
но пилися он больше месяца.
Напуствие ньюфагам - ЗАКРЫВАЙТЕ ФОРМЫ,
ЗАКРЫВАЙТЕ ЭТИ БЛЯДСКИЕ ФОРМЫ, я убил невероятно много времени на поиск бага, оказалось </form> отсутсовал И ЗАКРЫВАЙТЕ ЭТИ ФОРМЫ НАХУЙ
https://github.com/Merkalov/Students
Детище моё.
Залил на хостинг
http://students-list.ru.host1590257.serv66.hostland.pro/
Что бы не регаться используйте
Логин/пасс: totarin@r.ru
За ООП не поясню. За МВЦ раскидаю.
Вместо PDO и mysqli использовал фреймворк Medoo(который на PDO работает).
При заливке на хостиг сразу вылезли ошибки моей молодости(абсолютные/относительные пути, где-то вообще написан сам сайт(Students\list), вместо пути, за это уже понял не ругай.)
Куки на 10 лет + привязка к IP-адресу.
Версия php 5.5 - залил на хостинг, где 5.4 - сразу отвалилась авторизация с чудесным методом password_verify();
Код отформатировал встроенный в phpShtorm форматировщий(кроме Helper.php).
Собирался ещё допилить проверку полей через js, но руки не дошли. А так довольно занимательно в выходные проводить 10ч к ряду за написанием кода, забывая поесть.
Счётчик накрутил 54+ часа работы над проектом,
но пилися он больше месяца.
Напуствие ньюфагам - ЗАКРЫВАЙТЕ ФОРМЫ,
ЗАКРЫВАЙТЕ ЭТИ БЛЯДСКИЕ ФОРМЫ, я убил невероятно много времени на поиск бага, оказалось </form> отсутсовал И ЗАКРЫВАЙТЕ ЭТИ ФОРМЫ НАХУЙ
Брат, юзани пасс логин от татарина, на сервере осталый пхп, если авторизацию я мог быстро пофиксить, то с регистрацией там сложнее, не хочу перепиливать под старый пхп. Очевидно password_hash() и password_verify() из одной истории про пхп 5.5.
> totarin@r.ru
Идёт проверка по IP, поэтому когда кто-то заходит - другого выкидывает с этого аккаунта.
Починил регу.
надо из таблицы БД достать уникальные значения из столбца filters.
в уроке указано:
$tags=DB::table('portfolios')->distinct()->lists('filter');
но урок по версии ларавела 5.2, а нонче 5.4 и метода lists нема, гугл так говорит. подскажите плёс или в документацию харей ткните.
нашел вроде - его в pluck переименовали
> $urlGenerator->getDownloadUrl($file)
А нельзя назвать метод downloadFile (editFile, getLastFiles, getFile etc)? Ведь по названию класса видно, что возвращаться будут урлы.
win7, AMPPS, юзал АТОМ, щас пробую PHPStorm
downloadFile переводится как "скачать файл". Но функция не скачивает файл (а генерирует URL) и значит название не подходит.
нету когда я щяс забью жесть 2 урок и уже для эншейнтов какакието задачи((((( (
>Тут еще возможна ничья, когда нет даблов, но число очков одинаковое - это не проверяется.
Исправил, пикчу приклеил.
http://ideone.com/tMu8IN
>Слишком большое решение, например формула $creditBalance x $percent + $servicePayment встречается аж 3 раза, попробуй избавиться от повторов.
Откорректировал решение.
Формула с повторениями убрана. Можно убрать проверку на >0 и сокращение, тогда останется 20 строк. Но код будет менее универсальным.
http://ideone.com/xutDDU
>Тут можно обойтись без array_flip, просто взяв из массива значение по полученному индексу.
Тут создал новый код
http://ideone.com/Rvv9TQ
и старый
http://ideone.com/3YTUk6
Мне показалось второе решение менее громоздким. Но у тебя опыта больше, так что не спорю.
Из непроверенного и того что я сделал нового!
л33т. Тут я честно взял из википедии буквы, и прочитать результат сложновато, но видимо кто давно так пишет, приноровились уже это всё читать.
http://ideone.com/yvE1x7
Для примера:
$object = new Class($var1, $var2, $variablewithlongname3, $var4, $var5, $var6, $var7, $varvarvarvariable8, var9, var 10); — плохо
$object = new Class($parameters) — лучше, но разве мы видим так какие именно зависимости передаём? Ведь в отличие от класса в массиве нет на это указания или контекстной справки.
Я не вижу из этой ситуации выхода.
Но комментарий это плохо — для этого человеку придётся лезть в код класса или как минимум пользоваться продвинутой IDE.
По какой причине в конструктор нужно передавать 6-10 переменных? Они все нужны для работы класса?
Обычно зависимости - это объекты и путаницы нет из-за тайп-хинтов:
new UserService(UserTdg $userTdg, MailService $mailService, Cache $cache);
Лямбда — когда лень создавать отдельную функцию для какой-то задачи. Функцию поддерживать надо, не разбрасывать по всему скрипту, имя выдумывать, а лямбду сделал — и забыл. Замыкание то же самое, это лямбда, которая использует переменную из более общего скопа. Если читаешь по-английски, вот тут разжёвано http://culttt.com/2013/03/25/what-are-php-lambdas-and-closures/
Они удобны, когда нужно куда-то передать или сохранить список действий (операций).
Пример:
$numbers = range(1, 100);
$even = array_filter($numbers, function ($number) {
return $number % 2 == 0;
});
Также смотри функции array_map, usort.
Другой пример: допустим у тебя есть функция поиска товаров на складе. Как передать в нее критерии поиска ("найди мне товары производителя X ценой не более 200 тугриков")? Тут-то и пригодится анонимная функция.
Помоему лямбда в общем случае означает просто анонимную функцию. В пограмировании вроде больше принято лямбдами называеть стрелочный синтаксис (этакий апофеоз сахарной лени). Ну а замыкания проще всего понять на простом ооп без лишнего, например в джаве старенькой, чтобы прочувствовать все происходящее внутри дерьмо. Но это чисто мое мнение, не вдавался в академические термины, объяснял так паре чуваков на примерах.
Стоять они должны внутри круглых скобок. Да, там будет в любом случае ровно 2 точки с запятой, даже если какие-то из выражений отсутствуют.
> миллион в банке https://3v4l.org/heqou
Верно
Верно, хотя тут можно было использовать min или max вместо if
Правильно.
>>988958
Нужно различать веб-страницы и веб-приложения, а не бездумно повторять слова, увиденные в статье на хабре. И кстати в ОП посте есть задача на SPA, можешь попробовать сделать.
> namespace src\classes;
src не надо включать в неймспейс. Его надо либо убрать либо вписать туда название приложения. Также, неймспейсы желательно писать с большой буквы.
> https://github.com/some-random-username/student-list/blob/master/students.sql#L12
> DEFAULT CHARSET=latin1;
Что-то у тебя кодировка по умолчанию в БД кривая
> ADD UNIQUE KEY `id` (`id`);
Первичный ключ уже является уникальным по определению и второй ключ по id добавлять не надо.
https://github.com/some-random-username/student-list/blob/master/.htaccess
Чтобы сделать папку корнем, лучше в настройках сервера прописать ее как DocumentRoot, а не делать трюки с htaccess. Тем более что у тебя там аж 2 файла htaccess, и сложно оценить насколько они корректно будут работать во всех ситуациях.
> $code = $exception->getCode();
> http_response_code($code);
Это вообще не правильно так как поле $code в исключении не обязательно соответствует коду HTTP. Это в общем произвольное число. При выбросе исключения логично ставить код 503, а для ошибок 403/404 лучше сделать специальные отдельные классы исключений. Или формировать эти страницы без использования исключений.
> echo "<p>Message: '" . $exception->getMessage() . "'</p>";
Если строго смотреть то нельзя в HTML код просто так вставлять текст ошибки, его надо экранировать чтобы спецсимволы вроде <x> в нем выводились как есть, а не воспринимались бы как тег HTML.
> const CONFIGPATH = '../src/config.php';
Тут плохо что указан относительный путь, непонятно относительно чего, а также то, что тут использована глобально доступная константа. Лучше наверно сделать переменную и передавать ее только туда, где нужно.
https://github.com/some-random-username/student-list/tree/master/src/classes
classes - неудачное название так как ничего не значит. Тут пости везде классы. Лучше тогда просто положить эти классы в src
https://github.com/some-random-username/student-list/blob/master/src/classes/Application.php
Это правильнее назвать FrontController (погугли этот паттерн).
https://github.com/some-random-username/student-list/blob/master/src/classes/Router.php
РОутер обычно только анализирует URL, но не ищет контроллеры, это не его задача. А если он их ищет то это уже фронт контроллер и тогда непонятно зачем нужен класс Application.
Вообще, мне лично не нравится когда делают класс с названием Application - почти всегда он либо неправльно назван, либо в него сваливают все подряд. Ну что, разве твой Application представляет все приложение? Нет конечно, он лишь создает и запускает фронт контроллер, это сделать можно легко и без него.
https://github.com/some-random-username/student-list/blob/master/src/classes/Router.php#L60
Тут слишком много отступов. Также, если роутов нет то не надо возвращать false, лучше выбросить исключение, это ведь явно ошибка где-то.
Вот совет про пеерворачивание ифов: https://github.com/codedokode/pasta/blob/master/good-code.md#Переворачивай-большие-if
Вместо $this->params лучше использовать просто переменную.
> if(class_exists($controller)) {
Если такого класса нет то надо сообщать об ошибке, а не скрывать ее.
> public function removeQuery($url) {
Используй parse_url
> if(strpos($pieces[0], '=') === false) {
Это неправильно.
> '/\//'
Лучше использовать другие ограничители и бекслеш не понадобится: '~/~'
> https://github.com/some-random-username/student-list/blob/master/src/classes/Container.php#L52
> $this->values[] = $value;
Непонятно, зачем это в контейнере?
> public function offsetGet($offset) {
Если запрошен неверный сервис то лучше выдавать ошибку, а не скрывать ее.
Также, в твоем контейнере проблема в том, что при каждом обращении контейнер создает новый экземпляр сервиса, а часто нужно вернуть ранее созданный экземпляр.
Также, наверно лучше было не включать registerDefaults в контейнер, а заполнять контйенер в отдельном скрипте, например в bootstrap-скрипте.
https://github.com/some-random-username/student-list/blob/master/src/classes/Controller.php
тут странно что есть поле model, ты почему-то думаешь что каждый контроллер должен работать ровно с 1 моделью, а это не так. То же касается валидатора. Соответственно не стоит воогбще добавлять эти поля в базовый класс.
https://github.com/some-random-username/student-list/blob/master/src/classes/Template.php#L12
Если файла шаблона нет, то нужно сообщать об этом, а не скрывать ошибку. Вот для тебя написал совет: https://github.com/codedokode/pasta/blob/master/good-code.md#Не-скрывай-ошибки
https://github.com/some-random-username/student-list/blob/master/src/controllers/Students.php#L34
> if(isset($_GET['status']) and $_GET['status'] == 'added') {
Тут лучше было сделать отдельное действие (роут) или выводить уведомление над списком студентов.
Код для добавления и редактирования похож и не надо его дублировать (например вызов validate продублирован 2 раза).
> $errors = $this->validator->validate($_POST);
> $emailErrors = $this->validator->checkEmail($_POST['email']);
Непонятно почему проверить email нельзя в validate()
https://github.com/some-random-username/student-list/blob/master/src/models/Model.php
Непонятно почему тут 2 поля, db и pdo? Одного чего-то недостаточно?
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php
Модель не должна работать с $_GET. Перечитай урок про MVC. Идея в разделении кода, который анализирует параметры запроса, от кода который выполняет действие, а у тебя разделения нет.
Также класс для работы с БД не должен ставить куки.
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php#L21
ты подставляешь $sort в запрос, но он тут нигде не проверяется и получается SQL-инъекция.
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php#L27
зачем копировать данные из одного массива в другой? есть функция, получающая все строки сразу.
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php#L39
Ты все перемешал: и получение списка студентов, и подсчет их количества, и расчет пагинации. Это надо делать в разных функциях.
Представлять студента удобнее в виде объекта, а не массива.
> public function findStudent($findParam) {
Если список пустой то надо возвращать пустой массив, а не false. Иначе неудобюно работать с результатом функции.
Класс StudentsModel не должен заниматься авторизацией.
https://github.com/some-random-username/student-list/blob/master/src/helpers/md5.php
Класс должен называться с большой буквы, название неудачное так как это не класс для генерации md5 хешей, а класс для генерации и проверки хешей паролей.
https://github.com/some-random-username/student-list/blob/master/src/helpers/md5.php#L7
> (md5(random_int(100,999)
Сколько вариантов значений может вернуть эта функция? 899? Это же смешное количество, их можно перебрать за несколько секунд.
Сам класс сделан неправильно, должны быть такие функции:
- захешировать пароль
- проверить пароль
https://github.com/some-random-username/student-list/blob/master/src/helpers/Paginator.php
Не стоит HTML код класть сюда, лучше сделать шаблон.
https://github.com/some-random-username/student-list/blob/master/src/helpers/validators/Validator.php
Это класс подразумевает что все валидаторы должны работать с БД? Но это ведь не так, может быть валидатор и без БД, может быть валидатор с какими-то еще зависимостями.
Зачем тут вообще наследование? Не надо делать наследование "чтобы было", должна быть какая-то причина его вводить.
https://github.com/some-random-username/student-list/blob/master/src/helpers/validators/StudentsValidator.php
> public function __construct($container) {
Это паттерн service locator, а лучше использовать тут DI.
Работу с БД лучше делать в классе для работы с БД, а не в валидаторе. Каждый должен заниматься своим делом, иметь свою зону ответственности.
Шаблон редактирвоания и добавления - это почти копии друг друга, не надо дублировать код.
> <?=@htmlspecialchars($params['values']['lastname'],
Не используй @ так как он скрывает любые ошибки (например если ты опечатаешься в слове params или values то не узнаешь об этом).
Вообще плохо что у тебя в шаблоне все данные в $params, лучше в отдельных переменных их хранить.
> if(isset($params['errors'])):?
Плохо что переменная может быть, а может не быть.
При повторном выводе формы пол не сохраняется.
> namespace src\classes;
src не надо включать в неймспейс. Его надо либо убрать либо вписать туда название приложения. Также, неймспейсы желательно писать с большой буквы.
> https://github.com/some-random-username/student-list/blob/master/students.sql#L12
> DEFAULT CHARSET=latin1;
Что-то у тебя кодировка по умолчанию в БД кривая
> ADD UNIQUE KEY `id` (`id`);
Первичный ключ уже является уникальным по определению и второй ключ по id добавлять не надо.
https://github.com/some-random-username/student-list/blob/master/.htaccess
Чтобы сделать папку корнем, лучше в настройках сервера прописать ее как DocumentRoot, а не делать трюки с htaccess. Тем более что у тебя там аж 2 файла htaccess, и сложно оценить насколько они корректно будут работать во всех ситуациях.
> $code = $exception->getCode();
> http_response_code($code);
Это вообще не правильно так как поле $code в исключении не обязательно соответствует коду HTTP. Это в общем произвольное число. При выбросе исключения логично ставить код 503, а для ошибок 403/404 лучше сделать специальные отдельные классы исключений. Или формировать эти страницы без использования исключений.
> echo "<p>Message: '" . $exception->getMessage() . "'</p>";
Если строго смотреть то нельзя в HTML код просто так вставлять текст ошибки, его надо экранировать чтобы спецсимволы вроде <x> в нем выводились как есть, а не воспринимались бы как тег HTML.
> const CONFIGPATH = '../src/config.php';
Тут плохо что указан относительный путь, непонятно относительно чего, а также то, что тут использована глобально доступная константа. Лучше наверно сделать переменную и передавать ее только туда, где нужно.
https://github.com/some-random-username/student-list/tree/master/src/classes
classes - неудачное название так как ничего не значит. Тут пости везде классы. Лучше тогда просто положить эти классы в src
https://github.com/some-random-username/student-list/blob/master/src/classes/Application.php
Это правильнее назвать FrontController (погугли этот паттерн).
https://github.com/some-random-username/student-list/blob/master/src/classes/Router.php
РОутер обычно только анализирует URL, но не ищет контроллеры, это не его задача. А если он их ищет то это уже фронт контроллер и тогда непонятно зачем нужен класс Application.
Вообще, мне лично не нравится когда делают класс с названием Application - почти всегда он либо неправльно назван, либо в него сваливают все подряд. Ну что, разве твой Application представляет все приложение? Нет конечно, он лишь создает и запускает фронт контроллер, это сделать можно легко и без него.
https://github.com/some-random-username/student-list/blob/master/src/classes/Router.php#L60
Тут слишком много отступов. Также, если роутов нет то не надо возвращать false, лучше выбросить исключение, это ведь явно ошибка где-то.
Вот совет про пеерворачивание ифов: https://github.com/codedokode/pasta/blob/master/good-code.md#Переворачивай-большие-if
Вместо $this->params лучше использовать просто переменную.
> if(class_exists($controller)) {
Если такого класса нет то надо сообщать об ошибке, а не скрывать ее.
> public function removeQuery($url) {
Используй parse_url
> if(strpos($pieces[0], '=') === false) {
Это неправильно.
> '/\//'
Лучше использовать другие ограничители и бекслеш не понадобится: '~/~'
> https://github.com/some-random-username/student-list/blob/master/src/classes/Container.php#L52
> $this->values[] = $value;
Непонятно, зачем это в контейнере?
> public function offsetGet($offset) {
Если запрошен неверный сервис то лучше выдавать ошибку, а не скрывать ее.
Также, в твоем контейнере проблема в том, что при каждом обращении контейнер создает новый экземпляр сервиса, а часто нужно вернуть ранее созданный экземпляр.
Также, наверно лучше было не включать registerDefaults в контейнер, а заполнять контйенер в отдельном скрипте, например в bootstrap-скрипте.
https://github.com/some-random-username/student-list/blob/master/src/classes/Controller.php
тут странно что есть поле model, ты почему-то думаешь что каждый контроллер должен работать ровно с 1 моделью, а это не так. То же касается валидатора. Соответственно не стоит воогбще добавлять эти поля в базовый класс.
https://github.com/some-random-username/student-list/blob/master/src/classes/Template.php#L12
Если файла шаблона нет, то нужно сообщать об этом, а не скрывать ошибку. Вот для тебя написал совет: https://github.com/codedokode/pasta/blob/master/good-code.md#Не-скрывай-ошибки
https://github.com/some-random-username/student-list/blob/master/src/controllers/Students.php#L34
> if(isset($_GET['status']) and $_GET['status'] == 'added') {
Тут лучше было сделать отдельное действие (роут) или выводить уведомление над списком студентов.
Код для добавления и редактирования похож и не надо его дублировать (например вызов validate продублирован 2 раза).
> $errors = $this->validator->validate($_POST);
> $emailErrors = $this->validator->checkEmail($_POST['email']);
Непонятно почему проверить email нельзя в validate()
https://github.com/some-random-username/student-list/blob/master/src/models/Model.php
Непонятно почему тут 2 поля, db и pdo? Одного чего-то недостаточно?
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php
Модель не должна работать с $_GET. Перечитай урок про MVC. Идея в разделении кода, который анализирует параметры запроса, от кода который выполняет действие, а у тебя разделения нет.
Также класс для работы с БД не должен ставить куки.
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php#L21
ты подставляешь $sort в запрос, но он тут нигде не проверяется и получается SQL-инъекция.
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php#L27
зачем копировать данные из одного массива в другой? есть функция, получающая все строки сразу.
https://github.com/some-random-username/student-list/blob/master/src/models/StudentsModel.php#L39
Ты все перемешал: и получение списка студентов, и подсчет их количества, и расчет пагинации. Это надо делать в разных функциях.
Представлять студента удобнее в виде объекта, а не массива.
> public function findStudent($findParam) {
Если список пустой то надо возвращать пустой массив, а не false. Иначе неудобюно работать с результатом функции.
Класс StudentsModel не должен заниматься авторизацией.
https://github.com/some-random-username/student-list/blob/master/src/helpers/md5.php
Класс должен называться с большой буквы, название неудачное так как это не класс для генерации md5 хешей, а класс для генерации и проверки хешей паролей.
https://github.com/some-random-username/student-list/blob/master/src/helpers/md5.php#L7
> (md5(random_int(100,999)
Сколько вариантов значений может вернуть эта функция? 899? Это же смешное количество, их можно перебрать за несколько секунд.
Сам класс сделан неправильно, должны быть такие функции:
- захешировать пароль
- проверить пароль
https://github.com/some-random-username/student-list/blob/master/src/helpers/Paginator.php
Не стоит HTML код класть сюда, лучше сделать шаблон.
https://github.com/some-random-username/student-list/blob/master/src/helpers/validators/Validator.php
Это класс подразумевает что все валидаторы должны работать с БД? Но это ведь не так, может быть валидатор и без БД, может быть валидатор с какими-то еще зависимостями.
Зачем тут вообще наследование? Не надо делать наследование "чтобы было", должна быть какая-то причина его вводить.
https://github.com/some-random-username/student-list/blob/master/src/helpers/validators/StudentsValidator.php
> public function __construct($container) {
Это паттерн service locator, а лучше использовать тут DI.
Работу с БД лучше делать в классе для работы с БД, а не в валидаторе. Каждый должен заниматься своим делом, иметь свою зону ответственности.
Шаблон редактирвоания и добавления - это почти копии друг друга, не надо дублировать код.
> <?=@htmlspecialchars($params['values']['lastname'],
Не используй @ так как он скрывает любые ошибки (например если ты опечатаешься в слове params или values то не узнаешь об этом).
Вообще плохо что у тебя в шаблоне все данные в $params, лучше в отдельных переменных их хранить.
> if(isset($params['errors'])):?
Плохо что переменная может быть, а может не быть.
При повторном выводе формы пол не сохраняется.
$word1
$word2
хочу чето типо
$i = mt_rand(1,2)
$word$i
только оно не хочет
можно это сделать как-нибудь Без массивов из массивов?
Подозрительная замануха - не стал проходить туда.
спс
что-то через массивы массивов попробовал, тоже ничего не получает
например
$shlyapi = array (
array('fedora','ushanka'),
array('vagina','nosok'))
$shlyapi[1] получается выбирает полный массив с 0 = > fedora 1 => ushanka, а как выбрать еще из этого массивая только ушанку?
как $shyalpi[1[1]] токо чтобы работало (-:
include('./functions.php');
в каждом файле. Это правильное решение?
Хорошо, хорошо, я осознал глубину своей неправоты и трепещу перед твоими божественными знаниями. Так как надо-то?
Сложно сказать. Думаю, раз ты дошел до того, что у тебя какое-то дикое месиво из функций инклюдится в файлы, притом еще и в первый раз, чтобы код не повторять, значит ты совсем ничего не знаешь об архитектуре и ооп. В таком случае тебе тут по урокам опа учиться, потом задачки поделать и сам все поймешь.
Если же ты знаешь про ооп, то почитай про автозагрузку и psr-4, ну и так же пасты опа про mvc и прочее. Не знаю, насколько тебе это актуально будет, но думаю что это оно. Как бы файлы с функциями подключать лет 15 как не дело вообще. Самому же проще будет в дальнейшем.
Если же тебе, впринципе, не нужно ничего знать и ты не собираешься дальше продолжать работать над беком, то можно и так оставить. Мало ли, может ты верстальщик, которому 1.5 скрипта нужно было подключить и на этом твое погружение в тему закончится.
>У меня есть несколько файлов php.
Ок.
>В каждый (ну, почти каждый) из них вызывается аяксом и что-то делает.
Такого не может быть, но аякс может передавать данные файлу и получать данные от сервера обратно.
>Там есть повторяющиеся куски кода, которые хочу вынести в отдельные функции, а сами функции в отдельный файл.
Молодец.
>Сейчас это сделал через
>include('./functions.php');
В зависимости от того что тебе надо есть
include
require
require_once
смотри что тебе больше подойдёт.
>Такого не может быть
Почему же не может? Есть несколько элементов интерфейса пользователя, которые активируют соответствующие js-скрипты. А уже эти скрипты собирают данные отправляют их соответствующему php-файлу (вроде url:"./add.php",). Потом получают ответ через echo (ну или echo json_encode) и что-то там меняют на странице.
>include
>require
Уже читал по ним документацию,
>require идентично include за исключением того, что при ошибке оно также выдаст фатальную ошибку уровня E_COMPILE_ERROR.
Разве что, действительно, заменить на require_once было бы лучше.
>Выражение require_once идентично require за исключением того, что PHP проверит, включался ли уже данный файл, и, если да, не будет включать его еще раз.
>>999007
>Если же ты знаешь про ооп, то почитай про автозагрузку и psr-4
Пока что не знаю. Вообще слабо представляю, зачем в php нужны классы. Изучение у меня идёт от проблемы к решению. Нужно сделать реакцию на действие пользователя без перезагрузки страницы - изучаю аякс. Нужен нативный календарь - изучаю jQuery. Изучение классов пока что не очевидно. Не вижу, куда прикрутить эту реактивную турбину к моей деревянной телеге.
>у тебя какое-то дикое месиво из функций инклюдится в файлы
Ну почему сразу "месиво"?
>>998999
Зачем писать пост без содержания? Если не можешь ответить на вопрос, то не надо отвечать.
Малаца, что подходишь к проблеме с практической точки зрения и не останавливаешься перед трудностями даже без знаний.
Но, как я и сказал, лучше подучи, потому что будет самому же проще в дальнейшем.
Достоинства от использования ооп и грамотного выстраивания архитектуры ты почувствуешь, когда твой проект начнет неприлично разрастаться.
Можешь еще фреймворк какой-нибудь попробовать, там уже все готовенькое в этом плане, главное не нахуевертить самому.
>>999021
Я ответил норм потом, отъебись.
В общем, да, нормальное, функции для того и придуманы.
Использовать лучше require_once, include хуже чем require, так как не завершает скрипт при ошибке.
>>999017
> Вообще слабо представляю, зачем в php нужны классы.
Если хочешь изучить, то читай учебник в ОП посте и решай задачи из него (ну или какой-нибудь другой учебник на свой выбор). Потому что без этого ты ничего серьезного не напишешь и в команде (использующей например фреймворк) работать не сможешь.
чето слоупочу уже несколько часов
почему он залупливаться начинает после elseif? https://ideone.com/Sh0dby
>} elseif ($number = 3) { $x = 1; $number = 4; }
Я не знаю с чем это связано, но зачем написано в строку? Я на секунду завис.
$result = "UPDATE table SET `$column_in_db` = '$cell_value' WHERE `id` = '$id_in_db'";
В нём имя столбца задаётся переменной извне.
Если переписать его для PDO, то получится
$stmt = $pdo->prepare('UPDATE table SET :column_in_db = :cell_value WHERE `id` = :id_in_db');
Но это не работает, потому что prepare переводит всё в строку и при вставке в запрос обрамляет кавычками.
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''klient' = 'jfdh' WHERE `id` = '541'' at line 1'
То есть, должно быть `klient` или просто klient, а у меня получается 'klient'
Как это порешать?
а есть какая-то разница?
нужно 2 строчки одинаковых
1 делает до нумбера 3 и х 4
и типо elseif должен по идеи нумбер до 4 поднять чтобы не циклилось с первым и x обратно на 1 вернуть т.к. он связан с вордами
и по итогу второй if должен то же самое делать что и 1
В двойные кавычки не надо брать переменную саму по себе.
Если поставил elseif, то так и продолжай, зачем там дальше идёт просто if?
Сильно переусложнил, надо проще.
Попробуй сначала добиться того, чтобы просто вывелось из массива одно случайное значение.
Затем это удвой с помощью цикла и после цикла прибавь такой же случайный вывод последней строки.
Ещё раздражают твои названия переменных.
>} elseif ($number = 3) { $x = 1; $number = 4; }
} elseif ($number === 3) { $x = 1; $number = 4; }
но первый if без elseif он выводит нормаль :(
https://ideone.com/LorAd1
for в самом for нельзя менять что ли?
спс заработало
Объясните, пожалуйста, все 4 вывода. Ящитаю это крипота, когда к статике можно обращаться через стрелку.
Через плейсхолдеры можно подставлять только числа и строки в кавычках (то есть данные), но не имена полей или таблиц.
Придется подставлять напрямую, тщательно проверив что переменная содержит только допустимые значения и SQL инъекции тут нет.
>>999211
Проверь, открой отладчик (ctrl + shift + I) на вкладке network и посмотри.
>>999225
Это странность PHP, связанная с историческими особенностями. Там по идее в некоторых случаях предупреждение должно выдаваться. Писать так не стоит.
>Придется подставлять напрямую
Это прямо так?
$stmt = $pdo->prepare('UPDATE table SET $column_in_db = :cell_value WHERE `id` = :id_in_db');
Вроде же нельзя туда переменные пихать?
>Проверь, открой отладчик (ctrl + shift + I) на вкладке network и посмотри.
Уже проверил - мы получаем все ответы, и со страницы где происходит редерект, и со страницы на которую происходит редирект, но на самой странице, с которой мы отправили данные, ничего не происходит. Что лучше сделать после завершения транзакции? Самому перенаправить с помощью скрипта?
Ну так редирект относится только к аякс-запросу, он говорит что результат выполнения запроса надо искать по другому URL. С чего бы браузер должен переходить на другую страницу?
То же самое будет если например при попытке загрузки картинки будет редирект - браузер не перейдет на другую страницу.
> Самому перенаправить с помощью скрипта?
Да.
Также, дам тебе в помощь советы по использованию аякса, вдруг пригодится: https://github.com/codedokode/pasta/blob/master/js/ajax.md
Один анон из фронт треда мне сказал, что пхп учится чуть ли не за день, достаточно прочесть доку. Но я вижу, тут все серьезнее. Меня интересует не продвинутый уровень пхп, а такой, которого будет достаточно для устройства веб-макакой, т.е. какие-то базовые решения для обычных заказных сайтов. Html css и базовый js освоил, но отшивают, говорят, мол лучше бы ты без JS был, но с пхп. За неделю реально вкатиться?
За месяц можно, если понимаешь алгоритмы, как использовать функции и прочую парашу.
Я свой первый говноскрипт набыдлокодил за 3 дня, не зная что такое echo и var_dump
скрипт юзал либу, парсил страничку на сайте и записывал строку в базу данных, из базы банных строилась таблица значений
function bar(Foo $foo) {
$prop = $foo->getProp()
echo $prop;
}
...или же кидать это свойство в метод...
function bar($prop) {
echo $prop;
}
постепенно узнаешь. Главное иметь желание и практиковаться. Писать хуевый код, много хуевого кода.
Главное писать, сука блять
Надо смотреть, что делает этот метод. Ну например если есть метод "найти юзера по id" то нелогично передавать в него комментарий - логично именно id. Вообще, как правило, удобнее требовать минимум данных, то есть например только id, а не весь комментарий.
Ошибка точь-в-точь такая же как и здесь http://discourse.slimframework.com/t/file-upload-error-handling/631/2
в точности до максимального количества байтов в логах:
>[Thu Aug 18 09:12:45 2016] PHP Warning: POST Content-Length of 19022680 bytes exceeds the limit of 8388608 bytes in Unknown on line 0
>8388608 bytes
за исключением того что MAX_FILE_SIZE ничего не дает, потому что стоит значение такое же как и в настройках апача (2048MB)
Проверяй настройки в phpinfo()
Там есть как минимум upload_max_filesize и max_post_size или как-то так: http://php.net/manual/ru/ini.core.php
Также проверяй коды ошибок
http://php.net/manual/ru/features.file-upload.common-pitfalls.php
http://php.net/manual/ru/features.file-upload.errors.php
спасибо
>post_max_size
Я даже не знал что такая настройка может быть. Если бы не этот тред, я бы никогда не научился чему-то стоящему. Скорей бы освоить слим и жс, чтобы дописать архив тредов!
Отдуши наговнокодил, через месяц даже не пойму как это говно работает
Эта статья про возможности php7 может вас заинтересовать, пусть она не самая лёгкая. Например, можно вызывать лямбды из полей класса с помощью скобок: ($this->callable)()
(раньше нужно было передавать лямбду в отдельную переменную и вызывать $var() или пользоваться call_user_func).
Есть два массива:
[1,2,3,4,5]
и
[5,4,3,2,1]
Как сравнить их так, чтобы найти соответствия числам в первом массиве числам во втором? И в этот момент выкинуть оповещение.
Через двойной foreach только приходит в голову и с условиями, если $valueFirst из первого массива равно $valueSecond из второго массива, но есть ли что проще и быстрее работающее?
>Запустим наш файл. Теперь поиском убедимся, что поиск по слову «проверим» и «realtime» выдает нам результаты. Если ты ищешь через SQL, а не через api, не забудь указать в запросе оба индекса (SELECT ( FROM index_news, rt_news ... )).
>(SELECT ( FROM index_news, rt_news ... ))
Что-то я сбит с толку от такого запроса. Попробовал найти примеры, но ничего не нашел, и вообще мне не совсем понятно как делать поиск по нескольким таблицам одновременно. Как это лучше сделать? Мне нужно научиться функции JOIN?
Ну так это уже несколько лет как не новость. А вот arrow functions и дженерики до сих пор не ввели, зато зачем-то голосуют за ИМХО бесполезный тайп-хинт: https://wiki.php.net/rfc/object-typehint
>>999836
Не совсем понятно, что ты хочешь. Если надо проверить равенство значений 2-х массивов без учёта порядка элементов, то самый простой способ это отсортировать оба массива через sort() а потом сравнить через ==
>Не совсем понятно, что ты хочешь. Если надо проверить равенство значений 2-х массивов без учёта порядка элементов, то самый простой способ это отсортировать оба массива через sort() а потом сравнить через ==
Нет, не равенство. В одном массиве у меня ID обязательных тестов, а в другом массиве у меня ID выполненных обязательных тестов. Я сравниваю массивы: если совпадает - выкидываю "выполнено", а если не совпадает - выкидываю ID не сделанного теста.
Почему так? Потому что это проще хранить в БД, проще управляться с этим.
Нет, нет то. Там при любом несовпадении просто выкинет его - и все. То есть там будет true или false.
Ну вот мне что нужно просто упростить: http://ideone.com/NVWmGu
Думал, есть какая перда-функция, которая просто сталкивает два одномерных массива и выдаёт из несовпадающих значений массив.
Походу, размечтался.
Перечитай описание array_diff еще раз.
Твой код показывает что ты вообще не знаешь функции для работы с массивами, раз используешь циклы.
А, точно, спасибо: http://ideone.com/QTimTG
Да, надо бы навернуть мануал, да все нет времени. Мануал-то говно, вот и с аррай_дифф не понятно было, когда посмотрел.
Надо преобразовать адрес в координаты с помощью геокодирования, затем искать точки в определенном радиусе от этих координат в БД.
>>989562
> $start*$percent
Этот код выполняет умножение, но никуда не сохраняет результат. Надо писать $x = $x * %y чтобы результат сохранялся.
>>989608
У тебя нет команды, которая бы увеличивала переменную $money. Она каждый раз получается одинаковая.
>>989954
break можно использовать только внутри цикла, а не после.
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>990038
Разница может быть из-за того что на твоей странице стоят какие-то дополнительные стили, которые применяются к элементам (например, может влиять box-sizing).
Чтобы проверить, ты можешь изучить кнопки в инструментах разработчика (ctrl + shift + I) на 2 сайтах и сравнить примененные к ним стили.
>>990206
Прочесть документацию и уметь его использовать, знать, какие в нем есть возможности.
>>990243
ОП предпочитает сохранять анонимность.
Надо преобразовать адрес в координаты с помощью геокодирования, затем искать точки в определенном радиусе от этих координат в БД.
>>989562
> $start*$percent
Этот код выполняет умножение, но никуда не сохраняет результат. Надо писать $x = $x * %y чтобы результат сохранялся.
>>989608
У тебя нет команды, которая бы увеличивала переменную $money. Она каждый раз получается одинаковая.
>>989954
break можно использовать только внутри цикла, а не после.
Попробуй переписать код внутри цикла примерно так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
«Платим» здесь значит уменьшаем долг и увеличиваем общую сумму выплаченного.
>>990038
Разница может быть из-за того что на твоей странице стоят какие-то дополнительные стили, которые применяются к элементам (например, может влиять box-sizing).
Чтобы проверить, ты можешь изучить кнопки в инструментах разработчика (ctrl + shift + I) на 2 сайтах и сравнить примененные к ним стили.
>>990206
Прочесть документацию и уметь его использовать, знать, какие в нем есть возможности.
>>990243
ОП предпочитает сохранять анонимность.
Вот, допустим, имеется веб-страница, на ней форма и кнопка сабмит. Нажимаем кнопку, данные из формы улетают пхп-скрипту. Скрипт первым делом проверяет, может ли юзер вообще это делать. Если да, то скрипт срабатывает. Если нет, то редиректит на страницу авторизации. Ну, тут вроде всё понятно.
А если мы работаем через аякс? Это же получится, что пхп-скрипт вернёт аяксу эту самую страницу редиректа, которую браузер попытается вставить в текущую. Аякс же для того и запиливался, чтобы без редиректов всё было. Как правильно такие вещи с ним организовать?
Аякс-запрос разумеется редиректить не должен, а должен вернуть сигнал об ошибке.
Если ты используешь JSON то можно вернуть объект вида
{"success": false, "error": "У вас нет прав, чтобы удалить пользователя"}
Если ты не используешь JSON то ситуация хуже. Ты можешь попробовать использовать код ошибки, ну например, 403 Forbidden - но это не очень хорошая идея так как непонятно как тут передавать сообщение об ошибке (JSOn-ом?) и эти коды легко спутать с кодами ошибок от веб-сервера если что-то не так.
По моему опыту, удобнее использовать именно JSON так как он позволяет возвращать несколько значений.
>>997929
Запилил две новые функции, редикта и подключения шаблонов. Говори чё ещё переделать. Про DI пасту вообще не видел, надо почитать.
Собственно у меня параноидальный вопрос: насколько актуальны материалы из шапки?
Просто хочу быть спокойным по этому поводу.
Актуальны. Показывай свой код. Если что, мы поправим. В этом впринципе и смысл треда.
Пишу INSERT INTO rt_files (id, newname) VALUES (1, 'name'); заместо newname я должен был сделать originalname и заместо 'name' вставляется значения 0.
Вот конфиг: https://github.com/someApprentice/filehosting/blob/master/config/sphinx.conf
Ещё, после обновления конфига ничего не меняется. Приходиться самому удалять rt-файлы и перезагружать(!) систему. И после перезагрузки ещё постоянно удаляется папка /var/run/sphinxsearch. Лучше перенести pid и все другие файлы сфинкса в другое место?
https://github.com/someApprentice/filehosting/blob/master/config/sphinx.conf#L34-L36
Как определить rt_field и rt_attr_uint, если нужен поиск только по одной колонке? Заполнить обе эти настройки одинаковыми значениями? У меня было сделано так, но, я подумал, что именно из-за этого не заполняется значение.
Ещё, при индексации я получаю сообщение "Skipping non-plain index 'rt'...", но я настроил точно так же как показано в документации http://sphinxsearch.com/docs/current/rt-overview.html
Вчера вроде всё работало. Я не помню.
Что я делаю не так с этим Сфинксом?
>Почему в Сфинксе при добавлении строки, в поле вставляется 0 заместо нужного значения?
Я не знаю как это работает, но тут не было ошибки. Я просто допустил другие при поиске.
Что означает переменная docs? Это количество найденных совпадений?
http://bobylquote.ru
https://github.com/grigoryMovchan/AphorismCMS
Кто давал советы по коду не буггуртите если не всё исправил. В этой поделке я уже не хочу что-то капитально менять. Все рекомендации взяты на заметку для следующих поделок.
Первый раз VDS с нуля настраивал. Так что там пиздец с безопасностью. За вечер более-менее настроил сервер и слава богу. Потом подробно буду разбираться.
Две трети ёбли в поделке было с админкой, но её не могу показать по понятным причинам. Откровенно говоря, я вообще эту хуйню, которую месяц писал, никому кроме анончика показать не могу lol
Выглядит красиво, в т.ч. описание на гитхабе. Как верстал визуальную часть? Где хостил? За месяц, на мой взгляд, не плохо. Только названия коммитом типа "make it better" это неинформативно, название должно давать кратко понять, что произошло, и желательно чтобы коммиыт на каждую переделку/фичу были разными. Алсо, папка vendor на гитхабе не нужна, достаточно composer.json и ненавязчивое напоминание о зависимостях в md.
Откуда ты взял идею контроллеров и прочего?
мимо
Старый пост, но надо на него ответить.
Я помню, я написал, что неправильно в модель передавать запрос, а ты в ответ приводишь пример из документации Laravel. Но разница с твоим кодом в том, что в Laravel метод store создается в контроллере.
Задача контроллера - обработать запрос и выдать ответ. Вот тут контроллер и делает такие вещи:
- проверяет параметры запроса на правильность
- если все ок, вызвает метод модели, который создает задачу и в который уже передаются параметры задачи (название), а не запрос
- выдает редирект
Обрати внимание, что тут мы можем создать задачу (вызвать $tasks->create(..)) и без объекта Request. То есть модель отдельно, обработка параметров запроса отдельно. В модель сам объект запроса не передается.
Единственное, что мне не очень нравится, это то, что валидация сделана в контроллере, а не в модели, что не дает возможность ее вызвать откуда-то из другого места. Мне кажется, это неудачное решение.
Также, еще не очень хорошо, что они вместо сущности исопльзуют массив (и это же есть в твоем коде - параметры создаваемой цитаты кладутся в массив). Возможно тут лучше было сделать объект, так как у массива нигде не определен список полей, в него нельзя добавлять методы. А в классе все это есть и к нему можно писать комментарии. То есть разробраться в коде с массивами намного сложнее, особенно когда он станет побольше чем hello world. В реальных приложениях в таких случаях получаются массивы по 10-20 полей, из которых часть к тому же может отстутствовать и разбираться или вносить изменения в такой код сложно.
То есть в том коде Laravel можно было бы сделать сущность Task с свойством $name, и делать примерно так:
$task = new Task;
$task->name = $request->name;
и далее уже объект $task передавать для валидации и для сохранения в БД. Конечно, класс требует написать чуть больше кода, но зато делает код намного понятнее (ну и конечно, с классами тоже не все так просто по мере развития приложения).
> Сейчас искать не буду. Там смысл был в том, чтобы суперглобальные переменные обрабатывались в отдельном классе, потому что может понадобится сделать с ними что-то специфическое, и напрямую не передавались в модель.
Ну это наверно к чему-то другому относится.
> Ок, я могу получить id из Request в контроллере и передать его в метод модели. А как тогда быть со вторым пиком? Неправильно написан Request и для данных из формы должен быть свой массив, который я должен получать из Request в контроллере и передавать в метод модели?
Нужно в контролллере создавать массив или объект, представляющий цитату, и этот объект/массив передавать в модель для валидации и вставки в БД. Так, чтобы код был разделен на части, чтобы мы могли и из какого-то другого места кода валидировать и добавлять цитаты.
У тебя там, я вижу, валидация делается в контроллере, а лучше было бы сделать это где-то в виде повторно используемого метода.
>>990324
в /wrk может быть
>>990350
Это отдельный языкпрограммирования. К HTML он напрямую не привязан, но его можно использовать, чтобы генерировать HTML-код (или любой текст в любом другом формате разметки), который будет потом отображаться в браузере.
К сожалению, некоторые учебники это не очень хорошщо объясняют и люди почему-то думают что PHP как-то неразрывно связан с HTML, но они никак не связаны. Просто программа на PHP выдает на выходе HTML-страницу, которую потом отобразит браузер.
Старый пост, но надо на него ответить.
Я помню, я написал, что неправильно в модель передавать запрос, а ты в ответ приводишь пример из документации Laravel. Но разница с твоим кодом в том, что в Laravel метод store создается в контроллере.
Задача контроллера - обработать запрос и выдать ответ. Вот тут контроллер и делает такие вещи:
- проверяет параметры запроса на правильность
- если все ок, вызвает метод модели, который создает задачу и в который уже передаются параметры задачи (название), а не запрос
- выдает редирект
Обрати внимание, что тут мы можем создать задачу (вызвать $tasks->create(..)) и без объекта Request. То есть модель отдельно, обработка параметров запроса отдельно. В модель сам объект запроса не передается.
Единственное, что мне не очень нравится, это то, что валидация сделана в контроллере, а не в модели, что не дает возможность ее вызвать откуда-то из другого места. Мне кажется, это неудачное решение.
Также, еще не очень хорошо, что они вместо сущности исопльзуют массив (и это же есть в твоем коде - параметры создаваемой цитаты кладутся в массив). Возможно тут лучше было сделать объект, так как у массива нигде не определен список полей, в него нельзя добавлять методы. А в классе все это есть и к нему можно писать комментарии. То есть разробраться в коде с массивами намного сложнее, особенно когда он станет побольше чем hello world. В реальных приложениях в таких случаях получаются массивы по 10-20 полей, из которых часть к тому же может отстутствовать и разбираться или вносить изменения в такой код сложно.
То есть в том коде Laravel можно было бы сделать сущность Task с свойством $name, и делать примерно так:
$task = new Task;
$task->name = $request->name;
и далее уже объект $task передавать для валидации и для сохранения в БД. Конечно, класс требует написать чуть больше кода, но зато делает код намного понятнее (ну и конечно, с классами тоже не все так просто по мере развития приложения).
> Сейчас искать не буду. Там смысл был в том, чтобы суперглобальные переменные обрабатывались в отдельном классе, потому что может понадобится сделать с ними что-то специфическое, и напрямую не передавались в модель.
Ну это наверно к чему-то другому относится.
> Ок, я могу получить id из Request в контроллере и передать его в метод модели. А как тогда быть со вторым пиком? Неправильно написан Request и для данных из формы должен быть свой массив, который я должен получать из Request в контроллере и передавать в метод модели?
Нужно в контролллере создавать массив или объект, представляющий цитату, и этот объект/массив передавать в модель для валидации и вставки в БД. Так, чтобы код был разделен на части, чтобы мы могли и из какого-то другого места кода валидировать и добавлять цитаты.
У тебя там, я вижу, валидация делается в контроллере, а лучше было бы сделать это где-то в виде повторно используемого метода.
>>990324
в /wrk может быть
>>990350
Это отдельный языкпрограммирования. К HTML он напрямую не привязан, но его можно использовать, чтобы генерировать HTML-код (или любой текст в любом другом формате разметки), который будет потом отображаться в браузере.
К сожалению, некоторые учебники это не очень хорошщо объясняют и люди почему-то думают что PHP как-то неразрывно связан с HTML, но они никак не связаны. Просто программа на PHP выдает на выходе HTML-страницу, которую потом отобразит браузер.
Я тут написал много текста, и что-то мне лень уже это переставлять и как-то структурировать. Тут очень много вещей, которые стоит посмотреть и изучить, если есть время. Потому что АПИ, да и JS-приложения, пишутся уже давно и тут много чего придумано.
> Как остановить setInterval, который был вызван в предыдущем событии?
Есть clearInterval, но проще использовать setTimeout.
> С этой функцией очень много проблем, например, она меняет контекст this на вызываемой функции и его нельзя поменять с помощью call.
Это тема (как можно задать this) разжевывается в учебниках по JS, например: https://learn.javascript.ru/objects-more
И может в моих задачах на JS что-то было такое, но я не уверен.
>Что нужно отправлять в ответ на успешный POST запрос?
Обычно ответ возвращают в виде JSON, и в нем содержится либо информация об успешном выполнении запроса, либо об ошибке. Некоторые используют коды состояния HTTP (2xx/5xx) для индикации результата выполнения запроса, можешь посмотреть примеры в яндексовых АПИ:
https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/input_params-docpage/
https://tech.yandex.ru/disk/api/concepts/about-docpage/
Ты не обрабатываешь ошибки. Видимо, уроки, которые ты читал, упускают такие важные вещи. Вот тебе тогда мои маленькие советы про использование аякса: https://github.com/codedokode/pasta/blob/master/js/ajax.md
>Как организовать конференции?
Отправляешь запрос к АПИ на создание конференции, опционально передаешь список участников, в ответ получаешь id этой конференции и можешь в нее писать. Возможно, стоит сделать обычные диалоги тоже "конференциями" из 2 человек ради унификации кода.
> Я имею ввиду, как проще было бы получать все контакты пользователя и его конференции один запросом
Я не думаю, что это обязательно, можно и не одним наверно. Хотя может быть как-то выбирать их вместе было бы удобнее.
> Как лучше сохранять не отправленные сообщения?
Можно сохранять их в localStorage. Но тогда есть риск, если пользователь на каком-нибудь общем компьютере набирал сообщение, то потом его может найти и прочесть другой человек. Можно сохранять сообщение на сервер. Но тогда может человек сотрет сообщение, а на сервере оно сохранится. Тоже некрасиво. Также, сохранение не будет работать в оффлайне.
В общем, если заботиться о приватности, то лучше сообщение никуда не сохранять, если не заботиться, то на сервер и/или в localstorage.
Вообще, оффлайн-работа - интересная тема, но конечно она сильно усложнит твой код, возможно его придется целиком переделать. Ведь мессенджер по большому счету, вполне может работать какое-то время в оффлайне. Например ты переключаешь на контакт, история не загружается, но ты можешь писать сообщения, которые отправятся при восстановлении связи с сервером. Мессенджер без оффлайн-работы на мобильных устройствах, например, неудобно использовать.
Еще одна вещь - мне кажется, хорошим тоном было бы до отправки сообщения в чате писать информацию о том, куда сохраняется история этого чата. Чтобы пользователь знал, где будут храниться его сообщения. Никто почти так не делает, я только один раз видел это в каком-то линуксовом мессенджере, он спрашивал, надо ли сохранять историю. И это многое говорит об отношении разработчиков к приватности пользователя.
> Как сделать уведомление о том что пользватель набирает сообщение?
Вообще, это как раз тот случай, когда на БД это реализовать неудобно. По идее да, клиент должен посылать уведомление на сервер, тот сохранять куда-то (в таблицу уведомлений?) и отдавать другому клиенту. Уведомление желательно сделать актуальным только на небольшой период времени, чтобы при отсоедиении клиента у его собеседника не висело это уведомление вечно.
В случае с использованием comet, вебсокетов или аналогичных технологий уведомление можно никуда не сохранять, а просто переслать от одного клиента другому (через демон-ретранслятор на сервере или может быть даже напрямую, если есть возможность установить peer-to-peer соединение между клиентами).
> Я правильно вывожу новые элементы?
Вообще, нет, это очень плохой код, так как невозможно понять структуру HTML кода и невозможно там что-то править. Какая-то нечитаемая каша получилась. Тут нужно использовать шаблонизатор (тысячи их):
https://garann.github.io/template-chooser/
https://www.google.ru/search?q=js+template+engine&newwindow=1&gbv=1&sei=qFAyWazpBsaMsgGrmrPoAQ
Условно к "шаблонизаторам" можно отнести еще knockout, react и часть фреймворка angular.
Вдобавок у тебя там по моему еще уязвимость XSS есть - что если имя пользователя содержит угловые скобки например?
> Ничего то что я называю методы отображения одним словом, например, $view->index()? Я имею ввиду, мы же всё равно пишем $view, писать $view->viewIndex() похоже на тавтологию.
Вообще, плохо. Лучше называть методы начиная с глагола, например, showIndex.
По коду:
> https://github.com/someApprentice/chat/blob/master/public/api/getcontacts.php
Здесь АПИ сделано плохо, при не-залогиненности не возвращается никакого осмысленного ответа, а просто ответ с кодом 200 и пустым телом ответа. Почитай документацию по АПИ яндекса, посмотри, как они делают.
Также, не очень понятно, почему ты для АПИ код контроллера пишешь прямо в файле, а для обычных страниц делаешь классы-контроллеры. Никакой разницы с точки зрения MVC между выдачей обычной страницы и обработкой АПИ-запроса нету.
Кстати, по поводу АПИ, думаю, тебе (кроме яндексовых АПИ) будет интересно почитать описание (на англ) АПИ мессенджера Телеграм: https://core.telegram.org/#getting-started или АПИ вконтакте: https://vk.com/dev/manuals
Обрати внимание, что АПИ обычно версионируют, то есть URL выглядт как https://example.com/api/v1/something - это позволяет плавно мигрировать на новые версии АПИ, не ломая совместимость для старых клиентов. Ты не исплоьзуешь роутер, но можешь сделать это, просто создав папку v1.
Также, некоторые разработчики активно используют возможности HTTP (дополнительные заголовки, методы вроде PUT/DELETE, коды ответов), а некоторые не используют.
Также, перед проектированием АПИ, советую почитать про REST и HATEOS (и далее, стандарт про шаблоны URL https://tools.ietf.org/html/rfc6570 ), но тут конечно есть разные мнения, ну к примеру в иделогии REST одним запросом нельзя получить несколько несвязанных массивов данных, а HATEOS раздувает размер ответа.
Также, когда ты делаешь АПИ, возможно тебе захочется его документировать, и тут есть готовый инструмент http://swagger.io/ , который генерирует удобную документацию из JSON/YAML-описания API. Это JSON-описание можно писать руками, можно генерировать. Так как там описываются параметры запросов, то это описание можно использовать и для документирования, и для проверки входных параметров. Даже если документация не нужна, все равно его можно использовать для проверки данных.
И еще там упоминается JSON Schema, это стандарт для описания формата JSON-объектов (с возможностью проверки их соответствия схеме) и его тоже можно глянуть.
Ну и конечно, если ты все это изучишь и у тебя останется время, АПИ можно покрыть автоматизированными тестами. Урок про тестирование где-то в шапке.
Я тут написал много текста, и что-то мне лень уже это переставлять и как-то структурировать. Тут очень много вещей, которые стоит посмотреть и изучить, если есть время. Потому что АПИ, да и JS-приложения, пишутся уже давно и тут много чего придумано.
> Как остановить setInterval, который был вызван в предыдущем событии?
Есть clearInterval, но проще использовать setTimeout.
> С этой функцией очень много проблем, например, она меняет контекст this на вызываемой функции и его нельзя поменять с помощью call.
Это тема (как можно задать this) разжевывается в учебниках по JS, например: https://learn.javascript.ru/objects-more
И может в моих задачах на JS что-то было такое, но я не уверен.
>Что нужно отправлять в ответ на успешный POST запрос?
Обычно ответ возвращают в виде JSON, и в нем содержится либо информация об успешном выполнении запроса, либо об ошибке. Некоторые используют коды состояния HTTP (2xx/5xx) для индикации результата выполнения запроса, можешь посмотреть примеры в яндексовых АПИ:
https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/input_params-docpage/
https://tech.yandex.ru/disk/api/concepts/about-docpage/
Ты не обрабатываешь ошибки. Видимо, уроки, которые ты читал, упускают такие важные вещи. Вот тебе тогда мои маленькие советы про использование аякса: https://github.com/codedokode/pasta/blob/master/js/ajax.md
>Как организовать конференции?
Отправляешь запрос к АПИ на создание конференции, опционально передаешь список участников, в ответ получаешь id этой конференции и можешь в нее писать. Возможно, стоит сделать обычные диалоги тоже "конференциями" из 2 человек ради унификации кода.
> Я имею ввиду, как проще было бы получать все контакты пользователя и его конференции один запросом
Я не думаю, что это обязательно, можно и не одним наверно. Хотя может быть как-то выбирать их вместе было бы удобнее.
> Как лучше сохранять не отправленные сообщения?
Можно сохранять их в localStorage. Но тогда есть риск, если пользователь на каком-нибудь общем компьютере набирал сообщение, то потом его может найти и прочесть другой человек. Можно сохранять сообщение на сервер. Но тогда может человек сотрет сообщение, а на сервере оно сохранится. Тоже некрасиво. Также, сохранение не будет работать в оффлайне.
В общем, если заботиться о приватности, то лучше сообщение никуда не сохранять, если не заботиться, то на сервер и/или в localstorage.
Вообще, оффлайн-работа - интересная тема, но конечно она сильно усложнит твой код, возможно его придется целиком переделать. Ведь мессенджер по большому счету, вполне может работать какое-то время в оффлайне. Например ты переключаешь на контакт, история не загружается, но ты можешь писать сообщения, которые отправятся при восстановлении связи с сервером. Мессенджер без оффлайн-работы на мобильных устройствах, например, неудобно использовать.
Еще одна вещь - мне кажется, хорошим тоном было бы до отправки сообщения в чате писать информацию о том, куда сохраняется история этого чата. Чтобы пользователь знал, где будут храниться его сообщения. Никто почти так не делает, я только один раз видел это в каком-то линуксовом мессенджере, он спрашивал, надо ли сохранять историю. И это многое говорит об отношении разработчиков к приватности пользователя.
> Как сделать уведомление о том что пользватель набирает сообщение?
Вообще, это как раз тот случай, когда на БД это реализовать неудобно. По идее да, клиент должен посылать уведомление на сервер, тот сохранять куда-то (в таблицу уведомлений?) и отдавать другому клиенту. Уведомление желательно сделать актуальным только на небольшой период времени, чтобы при отсоедиении клиента у его собеседника не висело это уведомление вечно.
В случае с использованием comet, вебсокетов или аналогичных технологий уведомление можно никуда не сохранять, а просто переслать от одного клиента другому (через демон-ретранслятор на сервере или может быть даже напрямую, если есть возможность установить peer-to-peer соединение между клиентами).
> Я правильно вывожу новые элементы?
Вообще, нет, это очень плохой код, так как невозможно понять структуру HTML кода и невозможно там что-то править. Какая-то нечитаемая каша получилась. Тут нужно использовать шаблонизатор (тысячи их):
https://garann.github.io/template-chooser/
https://www.google.ru/search?q=js+template+engine&newwindow=1&gbv=1&sei=qFAyWazpBsaMsgGrmrPoAQ
Условно к "шаблонизаторам" можно отнести еще knockout, react и часть фреймворка angular.
Вдобавок у тебя там по моему еще уязвимость XSS есть - что если имя пользователя содержит угловые скобки например?
> Ничего то что я называю методы отображения одним словом, например, $view->index()? Я имею ввиду, мы же всё равно пишем $view, писать $view->viewIndex() похоже на тавтологию.
Вообще, плохо. Лучше называть методы начиная с глагола, например, showIndex.
По коду:
> https://github.com/someApprentice/chat/blob/master/public/api/getcontacts.php
Здесь АПИ сделано плохо, при не-залогиненности не возвращается никакого осмысленного ответа, а просто ответ с кодом 200 и пустым телом ответа. Почитай документацию по АПИ яндекса, посмотри, как они делают.
Также, не очень понятно, почему ты для АПИ код контроллера пишешь прямо в файле, а для обычных страниц делаешь классы-контроллеры. Никакой разницы с точки зрения MVC между выдачей обычной страницы и обработкой АПИ-запроса нету.
Кстати, по поводу АПИ, думаю, тебе (кроме яндексовых АПИ) будет интересно почитать описание (на англ) АПИ мессенджера Телеграм: https://core.telegram.org/#getting-started или АПИ вконтакте: https://vk.com/dev/manuals
Обрати внимание, что АПИ обычно версионируют, то есть URL выглядт как https://example.com/api/v1/something - это позволяет плавно мигрировать на новые версии АПИ, не ломая совместимость для старых клиентов. Ты не исплоьзуешь роутер, но можешь сделать это, просто создав папку v1.
Также, некоторые разработчики активно используют возможности HTTP (дополнительные заголовки, методы вроде PUT/DELETE, коды ответов), а некоторые не используют.
Также, перед проектированием АПИ, советую почитать про REST и HATEOS (и далее, стандарт про шаблоны URL https://tools.ietf.org/html/rfc6570 ), но тут конечно есть разные мнения, ну к примеру в иделогии REST одним запросом нельзя получить несколько несвязанных массивов данных, а HATEOS раздувает размер ответа.
Также, когда ты делаешь АПИ, возможно тебе захочется его документировать, и тут есть готовый инструмент http://swagger.io/ , который генерирует удобную документацию из JSON/YAML-описания API. Это JSON-описание можно писать руками, можно генерировать. Так как там описываются параметры запросов, то это описание можно использовать и для документирования, и для проверки входных параметров. Даже если документация не нужна, все равно его можно использовать для проверки данных.
И еще там упоминается JSON Schema, это стандарт для описания формата JSON-объектов (с возможностью проверки их соответствия схеме) и его тоже можно глянуть.
Ну и конечно, если ты все это изучишь и у тебя останется время, АПИ можно покрыть автоматизированными тестами. Урок про тестирование где-то в шапке.
https://github.com/someApprentice/chat/blob/master/public/api/getmessages.php
Тут слишком большая вложенность блоков.
Также, я вижу в АПИ немало копипасти вида
> 'id' => $message->getId(),
> 'author' => $message->getAuthor()->getName(),
Может, это стоит хотя бы в функцию вынести (экспортирование данных из объекта).
Также, если ты отдаешь JSON, нужно выставлять (и проверять на клиенте) правильный Content-Type. Ну это же основы HTTP.
https://github.com/someApprentice/chat/blob/master/src/Model/Database.php
Тут, возможно, лучше было сделать на каждую сущность свой класс. Также, как и с валидацией.
> $user->setId($result['id']);
> $user->setLogin($result['login']);
> $user->setName($result['name']);
Возможно, тут стоит сделать метод для создания объекта из массива.
Также, нет SQL-дампа базы в репозитории.
Насчет проектирования БД - там тоже много тонкостей есть, можно делать нормальзованную схему, но лучше денормализовывать ради повышения производительности. Ну например, возьмем то же сообщение. Можно хранить его в одном экземпляре, а можно в двух - в inbox получателя и в outbox отправителя. Это может облегчить выборку последних N сообщений, так как твой запрос с OR вряд ли хорошо ложится на индексы (вдобавок у тебя еще и сортировки там нет).
Вообще, SQL базы не очень хорошо подходят для таких задач, насколько я знаю, все нагруженные чаты в итоге пишут какие-то свои хранилища, заточенные именно под хранение сообщений. Но это конечно долго и сложно.
Также, у тебя система никак не оптимизирована для работы с большими объемами данных. Что, если у пользователя тысячи сообщений - ты все их разом загружаешь? Что, если у него тысяча контактов и чатов? Тут надо предусматривать частичную выборку данных.
https://github.com/someApprentice/chat/blob/master/src/Model/Validator.php#L6
> const LOGIN_ERROR = "Логин должен быть короче 20 английских символов";
Константы обычно так не используют, константа сама по себе обозначает какой-то вариант, а что в ней хранится, не важно.
https://github.com/someApprentice/chat/blob/master/src/View/View.php
Тут не уверен, что нужно на каждый шаблон писать по функции. Обычно просто делают функцию вида render($template, array $variables), а подготовку переменных делают в контроллере.
> name="password" pattern="(.){6,20}"
Почему пароль ограничен 20 символами? Чтобы подбирать было проще?
> https://github.com/someApprentice/chat/blob/master/templates/chat.phtml#L24
> <div class="content"><?= $message->getContent() ?></div>
Тут не XSS?
В форме отправки нет защиты от XSRF.
composer.lock лучше не убирать из репозитория, так как он содержит конкретные номера версий библиотек, на которых код протестирован, и будет лучше, если пользователь поставит те же самые библиотеки. Обычно composer.lock не выгружают в случае библиотеки (так как это может вызвать конфликты с другими библиотеками), но у тебя приложение, и в нем вполне нормально использовать composer.lock.
https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
https://getcomposer.org/doc/02-libraries.md#lock-file
https://blog.engineyard.com/2014/composer-its-all-about-the-lock-file
Насчет MVC, там у тебя все запутано. Ну вот например тут модель лезет в DOM:
https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L51
Модель ведь по задумке должна хранить данные и реализовывать логику работы приложения, а не считать величину отступа где-то на странице. У тебя тут не MVC, а просто часть кода случайно помещена в классы с названиями Controller и Model.
> $('.contacts-not-found').remove();
Вот вместо постоянного копирования этих кусков кода, обычно удобнее найти элемент и сохранить ссылку на него в переменную и далее работать с этой ссылкой. Это сделает и код аккуратнее, и заодно и ускорит работу, так как $(..) имеет сложность O(N) от числа элементов DOM на странице, там оптимизирован только поиск по id.
Вот еще пример плохого использования jQuery: $('textarea[name="message"]').val($('textarea[name="message"]').val() + "\n");
Вообще, по поводу JS, я конечно могу дать такой урок про MVC, но учти, что он довольно сложный https://github.com/codedokode/pasta/blob/master/js/minesweeper-mvc.md Может быть ты что-то из него захочешь взять. Только помни, что не стоит переусложнять код без необходимости.
Если есть время, глянь Knockout и React, Vue, Angular, Angular-light. Также, сразу добавлю, когда авторы Реакта пишут что-то вроде "реакт быстрый потому что использует Virtual DOM, а не медленный DOM", это надо понимать как "реакт быстрее аналогичного решения, которое работало по тем же принципам (перегенерация вида при изменениях), но постоянно бы обращалось к DOM", а не как "реакт быстрее остальных подходов". Ну например для обновления диалога, я не уверен что подход реакта будет быстро работать, это надо мерять.
Также, у тебя по моему не очень удачно реализован переход по истории:
> Contreller.prototype.getConversation = function(withUser) {
> $.getJSON('api/getmessages.php?with=' + withUser, function(results) {
> window.history.pushState({}, '', '/conversation.php?with=' + withUser);
Во-первых, с историей лучше работать через JS-библиотеку, это позволит поддерживать браузеры без pushState(). Во-вторых, если со страницы диалогов вызвать эту функцию, в историю не запишется переход на ту же самую страницу? В-третьих, ты делаешь переход только после получения ответа, это плохо, так как при проблемах со связью и обновлении страницы переход не произойдет. Ну и нет обработки ошибок при выполнении запроса.
Вообще, для работы с историей, есть такая штука, как клиентский роутер: https://www.google.ru/search?q=js+router&newwindow=1&gbv=1&sei=TWEyWc6YBYLVsAHegKrACg
Их много, есть встроенные в фреймворки вроде Angular/React, есть отдельные.
Также, работу с АПИ наверно было бы лучше вынести в отдельный класс. Чтобы иметь возможность писать что-нибудь вроде backend.getMessages(...). Это позволит, может быть, позже туда вкрутить поддержку кеширования данных и оффлайн-режима.
В document.ready у тебя код идет стеной. Но лучше было бы, возможно, разбить экран на компоненты (список контактов, диалог и тд), и каждый реализовать в своем классе.
https://github.com/someApprentice/chat/blob/master/public/api/getmessages.php
Тут слишком большая вложенность блоков.
Также, я вижу в АПИ немало копипасти вида
> 'id' => $message->getId(),
> 'author' => $message->getAuthor()->getName(),
Может, это стоит хотя бы в функцию вынести (экспортирование данных из объекта).
Также, если ты отдаешь JSON, нужно выставлять (и проверять на клиенте) правильный Content-Type. Ну это же основы HTTP.
https://github.com/someApprentice/chat/blob/master/src/Model/Database.php
Тут, возможно, лучше было сделать на каждую сущность свой класс. Также, как и с валидацией.
> $user->setId($result['id']);
> $user->setLogin($result['login']);
> $user->setName($result['name']);
Возможно, тут стоит сделать метод для создания объекта из массива.
Также, нет SQL-дампа базы в репозитории.
Насчет проектирования БД - там тоже много тонкостей есть, можно делать нормальзованную схему, но лучше денормализовывать ради повышения производительности. Ну например, возьмем то же сообщение. Можно хранить его в одном экземпляре, а можно в двух - в inbox получателя и в outbox отправителя. Это может облегчить выборку последних N сообщений, так как твой запрос с OR вряд ли хорошо ложится на индексы (вдобавок у тебя еще и сортировки там нет).
Вообще, SQL базы не очень хорошо подходят для таких задач, насколько я знаю, все нагруженные чаты в итоге пишут какие-то свои хранилища, заточенные именно под хранение сообщений. Но это конечно долго и сложно.
Также, у тебя система никак не оптимизирована для работы с большими объемами данных. Что, если у пользователя тысячи сообщений - ты все их разом загружаешь? Что, если у него тысяча контактов и чатов? Тут надо предусматривать частичную выборку данных.
https://github.com/someApprentice/chat/blob/master/src/Model/Validator.php#L6
> const LOGIN_ERROR = "Логин должен быть короче 20 английских символов";
Константы обычно так не используют, константа сама по себе обозначает какой-то вариант, а что в ней хранится, не важно.
https://github.com/someApprentice/chat/blob/master/src/View/View.php
Тут не уверен, что нужно на каждый шаблон писать по функции. Обычно просто делают функцию вида render($template, array $variables), а подготовку переменных делают в контроллере.
> name="password" pattern="(.){6,20}"
Почему пароль ограничен 20 символами? Чтобы подбирать было проще?
> https://github.com/someApprentice/chat/blob/master/templates/chat.phtml#L24
> <div class="content"><?= $message->getContent() ?></div>
Тут не XSS?
В форме отправки нет защиты от XSRF.
composer.lock лучше не убирать из репозитория, так как он содержит конкретные номера версий библиотек, на которых код протестирован, и будет лучше, если пользователь поставит те же самые библиотеки. Обычно composer.lock не выгружают в случае библиотеки (так как это может вызвать конфликты с другими библиотеками), но у тебя приложение, и в нем вполне нормально использовать composer.lock.
https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
https://getcomposer.org/doc/02-libraries.md#lock-file
https://blog.engineyard.com/2014/composer-its-all-about-the-lock-file
Насчет MVC, там у тебя все запутано. Ну вот например тут модель лезет в DOM:
https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L51
Модель ведь по задумке должна хранить данные и реализовывать логику работы приложения, а не считать величину отступа где-то на странице. У тебя тут не MVC, а просто часть кода случайно помещена в классы с названиями Controller и Model.
> $('.contacts-not-found').remove();
Вот вместо постоянного копирования этих кусков кода, обычно удобнее найти элемент и сохранить ссылку на него в переменную и далее работать с этой ссылкой. Это сделает и код аккуратнее, и заодно и ускорит работу, так как $(..) имеет сложность O(N) от числа элементов DOM на странице, там оптимизирован только поиск по id.
Вот еще пример плохого использования jQuery: $('textarea[name="message"]').val($('textarea[name="message"]').val() + "\n");
Вообще, по поводу JS, я конечно могу дать такой урок про MVC, но учти, что он довольно сложный https://github.com/codedokode/pasta/blob/master/js/minesweeper-mvc.md Может быть ты что-то из него захочешь взять. Только помни, что не стоит переусложнять код без необходимости.
Если есть время, глянь Knockout и React, Vue, Angular, Angular-light. Также, сразу добавлю, когда авторы Реакта пишут что-то вроде "реакт быстрый потому что использует Virtual DOM, а не медленный DOM", это надо понимать как "реакт быстрее аналогичного решения, которое работало по тем же принципам (перегенерация вида при изменениях), но постоянно бы обращалось к DOM", а не как "реакт быстрее остальных подходов". Ну например для обновления диалога, я не уверен что подход реакта будет быстро работать, это надо мерять.
Также, у тебя по моему не очень удачно реализован переход по истории:
> Contreller.prototype.getConversation = function(withUser) {
> $.getJSON('api/getmessages.php?with=' + withUser, function(results) {
> window.history.pushState({}, '', '/conversation.php?with=' + withUser);
Во-первых, с историей лучше работать через JS-библиотеку, это позволит поддерживать браузеры без pushState(). Во-вторых, если со страницы диалогов вызвать эту функцию, в историю не запишется переход на ту же самую страницу? В-третьих, ты делаешь переход только после получения ответа, это плохо, так как при проблемах со связью и обновлении страницы переход не произойдет. Ну и нет обработки ошибок при выполнении запроса.
Вообще, для работы с историей, есть такая штука, как клиентский роутер: https://www.google.ru/search?q=js+router&newwindow=1&gbv=1&sei=TWEyWc6YBYLVsAHegKrACg
Их много, есть встроенные в фреймворки вроде Angular/React, есть отдельные.
Также, работу с АПИ наверно было бы лучше вынести в отдельный класс. Чтобы иметь возможность писать что-нибудь вроде backend.getMessages(...). Это позволит, может быть, позже туда вкрутить поддержку кеширования данных и оффлайн-режима.
В document.ready у тебя код идет стеной. Но лучше было бы, возможно, разбить экран на компоненты (список контактов, диалог и тд), и каждый реализовать в своем классе.
Очень часто, почти везде. У меня есть задачи на него в ОП посте в JS задачах.
>>990693
Ссылку можно открыть в новой вкладке. Простейший веб-сервер встроен в PHP - почитай ОП пост про установку PHP, про командную строку, и урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
Там имеется в виду программа-веб-сервер, а не дорогая железная коробка.
>>990730
Почему? Может он поедет в США и к 30 возьмет в ипотеку дом в Калифорнии по оверпрайснутой цене.
>>992497
> PDO незачем в кишки прятать, что если я захочу в конфигурации БД указать PostgreSQL, а не MySQL?
Это вряд ли имеет смысл, так как нужно, чтобы все SQL запросы соответствовали синтаксису MySQL и Postgres одновременно, а это сложно и почти никто поэтому не делает возможность выбора БД.
>>994072
Надо проверять не числа, а константы ($error == UPLOAD_OK).
Это (сравнение строки с true) опирается на тонкости преобразования типов, которые люди вряд ли помнят и потому трудно понять, что делает код и верно ли он написан. Если ты хочешь проверить, что строка не пуста, то так и надо писать ($s !== '').
>>997472
> Маркдаун не переваривает табы и игнорирует пробельные отступы.
Нужно оформить блок как код (с помощью отступа или 3 косых кавычек) и все будет нормально.
Такие вещи, которые нужны при разработке, но не при обычном использовании приложения, лучше помещать в require-dev.
> Алсоу, предложенный там вариант с strval не работает с массивами,
Да, с массивами лучше написать свою функцию для проверки, что это массив, что он содержит значения нужных типов и тд.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/autoload.php
Лучше по моему использовать один скрипт автозагрузки и для тестов и для обычного кода. И примерно то же самое с бустрапом, удобнее иметь один скрипт инициализации.
Для тестов обычно делают отдельную папку в корневой директории. Папку Shinoa создавать не требовалось, можно было просто подкрутить автозагрузчик.
https://github.com/Al-faqun/Students/blob/master/composer.json
Тут у тебя лишние поля, которые заполнены бессмысленной информацией. Если ты пишешь не библиотеку, то большинство их не нужны и лучше их убрать. Или заполнить.
> DIRECTORY_SEPARATOR
Можно использовать прямой слеш, работает везде.
Какой-то у тебя автозагрузчик сложный получился.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/root.php
Этот файл лучше убрать, а расположение папки проще определять через __DIR__
> public function tearDown()
> if ( !empty($this->insertedIds)) {
> foreach ($this->insertedIds as $userId) {
Есть более интересный метод - начать транзакцию в setUp и отменить ее в tearDown. Ну либо пересоздавать БД перед каждый тестом, но это тяжело. Либо писать такие тесты, чтобы они друг на друга не влияли.
> throw new DbException('Ошибка при получении хешей', 0, $e);
Надо добавлять userId в сообщение, иначе как потом расследовать эту ошибку?
> function getHash($userId)
> $this->sqlBuilder->select();
тут ты используешь объект у которого неизвестное начальное состояние. Правильнее создавать новый билдер. И вообще, я думаю что билдер тут не нужен, удобнее и быстрее написать SQL запрос, билдер используют, когда запрос может меняться в зависимости от условий.
> else $hash = false;
Нужны фигурные скобки
> public function testGetHash()
> $userid = 1;
> $hash = $this->mapper->getHash($userid)
Этот тест полагается на известное состояние БД. Было бы наверно лучше написать тест, который сначала вставляет хеш в БД, а потом пытается его прочесть - тогда он мог бы работать даже на пустой БД. Затем, можно написать тест, который вставляет запись, удаляет, пытается прочесть. И так далее.
> public function testGetHashWrongIDFail()
> $userid = 700000;
А как-то гарантируется, что в БД нет такого id?
> public function testGetHashIDAsStringFail()
> $userid = 'fdfdf1';
лучше 1fdfd, так как оно при преобразовании дает 1
> public function testGetHashIDAsStringFail()
> public function testGetHashIDAsArrayFail()
> public function testGetHashIDAsBoolFalse()
Вообще, если так писать для каждой функции, то объем тестов быстро растет. Такие вещи проще проверять тайпхинтами (в PHP7 ставится тайпхинт на числа), либо условием в начале функции.
Либо объединить их в один метод с массивом неправильных значений.
> public function testAddHashArrayFail()
> $result = $this->mapper->addHash($userid, $hash);
> $this->assertFalse($result);
Вообще при ошибке лучше выкидывать исключение, а не возвращать false, который никто потом не будет проверять.
> public function testCheckSortByWhiteList()
> $this->assertContains($sort_by, $this->sortbyWhitelist, 'Значение sort_by не из разрешённого списка');
Это плохая идея, проверять человеческие сообщения, так как стоит там переставить пару слов местами или добавить один пробел, как все сломается. Лучше проверять машинночитаемые значения, если их нет, можно просто проверить что массив сообщений не пуст.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/SearchQueryValidator.php#L84
> public function checkSortBy()
Тут трудно понять, как работает эта функция, так как она работает с какими-то массивами с неизвестным содеожимым. Вдобавок у этой функции нет аргументов.
> bool|mixed Returns string with field name on success, second field on false validation, or FALSE on internal logical error.
Это тоже понять трудно. Единственное, что я понял, что при логической ошибке лучше бросать исключение. Тем более, что я не вижу, где там возвращается false.
Функция должна возвращать значения одного типа, иначе с ней невозможно работать. Не должно быть такого, что функция возвращает то строку, то массив - это мина замедленного действия.
И кстати, у тебя много где возвращается false, а ты везде, в 100% случаях это проверяешь и обрабатываешь? Уверен, что нет. Надо использовать исключения и тогда проблемы не будет.
> if (array_key_exists($fieldname, $this->input)
> &&
> ( ($key = array_search($this->input[$fieldname], $this->fieldsWhitelist, false)) !== false )
Это тяжело читать, надо выносить части условия в переменные. Или сделать тут два if вместо одного.
Вообще, класс SearchQueryValidator какой-то странный, он там даже подсчетом числа страниц занимается зачем-то. Функции названы неправильно. Например, функцию checkPage() правильнее назвать getOffsetAndLimit(), убрать оттуда ссылки, а может, разбить на 2 функции. А еще лучше убрать этот $this->input и явно передавать в функию номер страницы. На мой взгляд, тут лучше вообще убрать $this->input из класса. И убрать расчет пагинации, так как он тут ни к селу, ни к городу.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/PassSQLBuilder.php
Этот класс какой-то переусложненный, трудно понять код в нем, и непонятно, почему у тебя 2 билдера, а не один универсальный.
> if (preg_match('/ORDER BY/ui', $this->sql) == 0) {
Это неправильно, так как слова ORDER BY могут встретиться внутри строки или подзапроса. Не надо тут анализировать SQL код, свойства запроса надо хранить в полях объекта.
> const DELETE_BY_ID = 'DELETE FROM <table_name> WHERE `userid` = :userid' . self::space;
Нет причины выносить это в константу.
Ну и ты там везде добавляешь COUNT_ROWS, но может он не всегда нужен. Он ведь влияет на производительность.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/StatusSelector.php
Что-то ты переусложнил тут все очень сильно.
В маппере не стоит преобразовывать исключения, так как это раздувает код, а на практике скорее всего никак не используется. Только если в учеюных целях, но тогда надо сделать сообщения более подробными.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/SearchQueryValidatorTest.php
Тут подозрительно много однотипных методов.
> $this->studentValidator->dataSent();
Название функции начинается с глагола.
> $this->studentValidator = new StudentValidator(new StudentMapper($this->pdo), $input);
> $datasent = $this->studentValidator->dataSent();
> $student = $this->studentValidator->checkInput($errors, $datasent)
Этот код какой-то переусложненный. Почему мы вызываем 2 функции? Что значит dataSent?
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/StudentValidatorTest.php
Тут тесты очень похожие, надо было сделать один тест и набор данных для него.
> array $inputArray Input, containing 'password' and 'user data' of current user of site.
> function __construct(PasswordMapper $mapper, array $inputArray)
Почему тут массив, а не просто 2 переменных password и user_data? Из за этого код только тяжелее читать становится.
И вообще, зачем в конструктор передавать пароль, если напимер метод logIn() их не использует? Как-то странно спроектирован класс.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/ErrEvoker.php#L25
> function isErrorIn(array $array)
Это какой-то очень странный метод, непонятно, что делающий в этом классе. Ну то есть если ты хочешь проверить, не нажата ли кнопка в форме, почему нельзя написать if в контроллере?
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/RegEditView.php
Это очень странный класс, и мне кажется что он не нужен. Также, метод output() - это явно кусок контроллера, а не view.
https://github.com/Al-faqun/Students/blob/master/templates/tpl_reg-edit.php#L3
> if (!isset($caption) || !isset($submitButName) || !isset($mesagge) || !isset($error)
Не надо так делать, надо сделать, чтобы эти переменные всегда существовали.
> !isset($defFields['mascVal']) || !isset($defFields['femVal'])
Проще передать один объект студента, у которого все нужные поля гарантированно существуют, чем мучаться с массивом. Тут нужен объект, а не массив.
Также, у тебя почему-то 2 шаблона формы регистрации, зачем?
В общем, там еще много чего надо исправлять, давай потихоньку разбираться, если что, пиши вопросы, так как я мог что-то непонятно написать. Пока код переусложнен, MVC тут какой-то странный, многие классы тоже спроектированы странно.
Это (сравнение строки с true) опирается на тонкости преобразования типов, которые люди вряд ли помнят и потому трудно понять, что делает код и верно ли он написан. Если ты хочешь проверить, что строка не пуста, то так и надо писать ($s !== '').
>>997472
> Маркдаун не переваривает табы и игнорирует пробельные отступы.
Нужно оформить блок как код (с помощью отступа или 3 косых кавычек) и все будет нормально.
Такие вещи, которые нужны при разработке, но не при обычном использовании приложения, лучше помещать в require-dev.
> Алсоу, предложенный там вариант с strval не работает с массивами,
Да, с массивами лучше написать свою функцию для проверки, что это массив, что он содержит значения нужных типов и тд.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/autoload.php
Лучше по моему использовать один скрипт автозагрузки и для тестов и для обычного кода. И примерно то же самое с бустрапом, удобнее иметь один скрипт инициализации.
Для тестов обычно делают отдельную папку в корневой директории. Папку Shinoa создавать не требовалось, можно было просто подкрутить автозагрузчик.
https://github.com/Al-faqun/Students/blob/master/composer.json
Тут у тебя лишние поля, которые заполнены бессмысленной информацией. Если ты пишешь не библиотеку, то большинство их не нужны и лучше их убрать. Или заполнить.
> DIRECTORY_SEPARATOR
Можно использовать прямой слеш, работает везде.
Какой-то у тебя автозагрузчик сложный получился.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/root.php
Этот файл лучше убрать, а расположение папки проще определять через __DIR__
> public function tearDown()
> if ( !empty($this->insertedIds)) {
> foreach ($this->insertedIds as $userId) {
Есть более интересный метод - начать транзакцию в setUp и отменить ее в tearDown. Ну либо пересоздавать БД перед каждый тестом, но это тяжело. Либо писать такие тесты, чтобы они друг на друга не влияли.
> throw new DbException('Ошибка при получении хешей', 0, $e);
Надо добавлять userId в сообщение, иначе как потом расследовать эту ошибку?
> function getHash($userId)
> $this->sqlBuilder->select();
тут ты используешь объект у которого неизвестное начальное состояние. Правильнее создавать новый билдер. И вообще, я думаю что билдер тут не нужен, удобнее и быстрее написать SQL запрос, билдер используют, когда запрос может меняться в зависимости от условий.
> else $hash = false;
Нужны фигурные скобки
> public function testGetHash()
> $userid = 1;
> $hash = $this->mapper->getHash($userid)
Этот тест полагается на известное состояние БД. Было бы наверно лучше написать тест, который сначала вставляет хеш в БД, а потом пытается его прочесть - тогда он мог бы работать даже на пустой БД. Затем, можно написать тест, который вставляет запись, удаляет, пытается прочесть. И так далее.
> public function testGetHashWrongIDFail()
> $userid = 700000;
А как-то гарантируется, что в БД нет такого id?
> public function testGetHashIDAsStringFail()
> $userid = 'fdfdf1';
лучше 1fdfd, так как оно при преобразовании дает 1
> public function testGetHashIDAsStringFail()
> public function testGetHashIDAsArrayFail()
> public function testGetHashIDAsBoolFalse()
Вообще, если так писать для каждой функции, то объем тестов быстро растет. Такие вещи проще проверять тайпхинтами (в PHP7 ставится тайпхинт на числа), либо условием в начале функции.
Либо объединить их в один метод с массивом неправильных значений.
> public function testAddHashArrayFail()
> $result = $this->mapper->addHash($userid, $hash);
> $this->assertFalse($result);
Вообще при ошибке лучше выкидывать исключение, а не возвращать false, который никто потом не будет проверять.
> public function testCheckSortByWhiteList()
> $this->assertContains($sort_by, $this->sortbyWhitelist, 'Значение sort_by не из разрешённого списка');
Это плохая идея, проверять человеческие сообщения, так как стоит там переставить пару слов местами или добавить один пробел, как все сломается. Лучше проверять машинночитаемые значения, если их нет, можно просто проверить что массив сообщений не пуст.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/SearchQueryValidator.php#L84
> public function checkSortBy()
Тут трудно понять, как работает эта функция, так как она работает с какими-то массивами с неизвестным содеожимым. Вдобавок у этой функции нет аргументов.
> bool|mixed Returns string with field name on success, second field on false validation, or FALSE on internal logical error.
Это тоже понять трудно. Единственное, что я понял, что при логической ошибке лучше бросать исключение. Тем более, что я не вижу, где там возвращается false.
Функция должна возвращать значения одного типа, иначе с ней невозможно работать. Не должно быть такого, что функция возвращает то строку, то массив - это мина замедленного действия.
И кстати, у тебя много где возвращается false, а ты везде, в 100% случаях это проверяешь и обрабатываешь? Уверен, что нет. Надо использовать исключения и тогда проблемы не будет.
> if (array_key_exists($fieldname, $this->input)
> &&
> ( ($key = array_search($this->input[$fieldname], $this->fieldsWhitelist, false)) !== false )
Это тяжело читать, надо выносить части условия в переменные. Или сделать тут два if вместо одного.
Вообще, класс SearchQueryValidator какой-то странный, он там даже подсчетом числа страниц занимается зачем-то. Функции названы неправильно. Например, функцию checkPage() правильнее назвать getOffsetAndLimit(), убрать оттуда ссылки, а может, разбить на 2 функции. А еще лучше убрать этот $this->input и явно передавать в функию номер страницы. На мой взгляд, тут лучше вообще убрать $this->input из класса. И убрать расчет пагинации, так как он тут ни к селу, ни к городу.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/PassSQLBuilder.php
Этот класс какой-то переусложненный, трудно понять код в нем, и непонятно, почему у тебя 2 билдера, а не один универсальный.
> if (preg_match('/ORDER BY/ui', $this->sql) == 0) {
Это неправильно, так как слова ORDER BY могут встретиться внутри строки или подзапроса. Не надо тут анализировать SQL код, свойства запроса надо хранить в полях объекта.
> const DELETE_BY_ID = 'DELETE FROM <table_name> WHERE `userid` = :userid' . self::space;
Нет причины выносить это в константу.
Ну и ты там везде добавляешь COUNT_ROWS, но может он не всегда нужен. Он ведь влияет на производительность.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/StatusSelector.php
Что-то ты переусложнил тут все очень сильно.
В маппере не стоит преобразовывать исключения, так как это раздувает код, а на практике скорее всего никак не используется. Только если в учеюных целях, но тогда надо сделать сообщения более подробными.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/SearchQueryValidatorTest.php
Тут подозрительно много однотипных методов.
> $this->studentValidator->dataSent();
Название функции начинается с глагола.
> $this->studentValidator = new StudentValidator(new StudentMapper($this->pdo), $input);
> $datasent = $this->studentValidator->dataSent();
> $student = $this->studentValidator->checkInput($errors, $datasent)
Этот код какой-то переусложненный. Почему мы вызываем 2 функции? Что значит dataSent?
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/Tests/StudentValidatorTest.php
Тут тесты очень похожие, надо было сделать один тест и набор данных для него.
> array $inputArray Input, containing 'password' and 'user data' of current user of site.
> function __construct(PasswordMapper $mapper, array $inputArray)
Почему тут массив, а не просто 2 переменных password и user_data? Из за этого код только тяжелее читать становится.
И вообще, зачем в конструктор передавать пароль, если напимер метод logIn() их не использует? Как-то странно спроектирован класс.
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/ErrEvoker.php#L25
> function isErrorIn(array $array)
Это какой-то очень странный метод, непонятно, что делающий в этом классе. Ну то есть если ты хочешь проверить, не нажата ли кнопка в форме, почему нельзя написать if в контроллере?
https://github.com/Al-faqun/Students/blob/master/Shinoa/StudentsList/RegEditView.php
Это очень странный класс, и мне кажется что он не нужен. Также, метод output() - это явно кусок контроллера, а не view.
https://github.com/Al-faqun/Students/blob/master/templates/tpl_reg-edit.php#L3
> if (!isset($caption) || !isset($submitButName) || !isset($mesagge) || !isset($error)
Не надо так делать, надо сделать, чтобы эти переменные всегда существовали.
> !isset($defFields['mascVal']) || !isset($defFields['femVal'])
Проще передать один объект студента, у которого все нужные поля гарантированно существуют, чем мучаться с массивом. Тут нужен объект, а не массив.
Также, у тебя почему-то 2 шаблона формы регистрации, зачем?
В общем, там еще много чего надо исправлять, давай потихоньку разбираться, если что, пиши вопросы, так как я мог что-то непонятно написать. Пока код переусложнен, MVC тут какой-то странный, многие классы тоже спроектированы странно.
> https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Core/ErrorHandler.php#L37
> // 0 - проект на тестовом сервере, 1 - проект на общедоступном сервере
Надо использовать либо константы, либо true/false. Числа используются для выражения количества чего-то.
> if ($appStatus !== 0) {
> set_exception_handler(function ($e) {
Не вижу смысла отключать обработчик на dev
> set_error_handler(function ($errno, $errstr, $errfile, $errline) {
> self::addToLog($errno, $errstr, $errfile, $errline);
Это не нужно так как исключение будет залоггировано, если не перехвачено. А если оно перехвачено, значит логгировать не требуется.
> self::ensure(!is_null($appStatus), "Не удалось получить настройку режима работы приложения.");
Проверку аргументов функции надо ставить в начале. Я бы поставил is_bool тогда.
> static public function getConfigElement($elemName)
Непонятно, что работа с конфигом делает в обработчике ошибок.
Логгировать удобнее в стандартный файл ошибок, а не в отдельный файл. Проверять размер лога тогда не потребуется, так как этим занимается отдельный скрипт logrotate в линуксе. Мне кажется, ты зря изобрел свою систему логгирования. Ну и кстати, если ты захочешоь именно свою систему логгирования, бери готовую PSR-совместимую библиотеку логгера.
>>997691
> Что бы защититься от уязвимости sql - нужно санитайзить переменные непосредственно перед тем как он попадет в базу? Если например нет возможности удостовериться, что селекты и инсерты выполняются через плейсхолдеры где-то там в ядре фремворка, на котором написан проект, правильно?
Если нет возможности убедиться, то там может быть произвольное число уязвимостей. Можно конечно каким-нибудь сканером потыкать, но не факт что он их найдет.
> То это уже во вьюхе при выводе инфы от юзеров в шаблон нужно обмазывать? Что бы потенциальный js код не поставился во вьюху и не выполнился вредоносно?
Конечно, это XSS называется.
> Что по поводу аплоада файлов, ни слова не сказано как защититься от загрузки pidor.php в папку с аватарками и дальнейшим доступом ко всему коду / в админку проекта.
Есть немного информации в задаче про файлообменник https://gist.github.com/codedokode/9424217
> https://github.com/grigoryMovchan/AphorismCMS/blob/master/app/Core/ErrorHandler.php#L37
> // 0 - проект на тестовом сервере, 1 - проект на общедоступном сервере
Надо использовать либо константы, либо true/false. Числа используются для выражения количества чего-то.
> if ($appStatus !== 0) {
> set_exception_handler(function ($e) {
Не вижу смысла отключать обработчик на dev
> set_error_handler(function ($errno, $errstr, $errfile, $errline) {
> self::addToLog($errno, $errstr, $errfile, $errline);
Это не нужно так как исключение будет залоггировано, если не перехвачено. А если оно перехвачено, значит логгировать не требуется.
> self::ensure(!is_null($appStatus), "Не удалось получить настройку режима работы приложения.");
Проверку аргументов функции надо ставить в начале. Я бы поставил is_bool тогда.
> static public function getConfigElement($elemName)
Непонятно, что работа с конфигом делает в обработчике ошибок.
Логгировать удобнее в стандартный файл ошибок, а не в отдельный файл. Проверять размер лога тогда не потребуется, так как этим занимается отдельный скрипт logrotate в линуксе. Мне кажется, ты зря изобрел свою систему логгирования. Ну и кстати, если ты захочешоь именно свою систему логгирования, бери готовую PSR-совместимую библиотеку логгера.
>>997691
> Что бы защититься от уязвимости sql - нужно санитайзить переменные непосредственно перед тем как он попадет в базу? Если например нет возможности удостовериться, что селекты и инсерты выполняются через плейсхолдеры где-то там в ядре фремворка, на котором написан проект, правильно?
Если нет возможности убедиться, то там может быть произвольное число уязвимостей. Можно конечно каким-нибудь сканером потыкать, но не факт что он их найдет.
> То это уже во вьюхе при выводе инфы от юзеров в шаблон нужно обмазывать? Что бы потенциальный js код не поставился во вьюху и не выполнился вредоносно?
Конечно, это XSS называется.
> Что по поводу аплоада файлов, ни слова не сказано как защититься от загрузки pidor.php в папку с аватарками и дальнейшим доступом ко всему коду / в админку проекта.
Есть немного информации в задаче про файлообменник https://gist.github.com/codedokode/9424217
> алсо, какое пастохранилище использовать лучше пастбина?)
gist.github.com если есть гитхаб
> if ( array_key_exists($name, $this->objects) ) {
> $result = $this->objects[$name];
Лучше сразу return, читать будет проще и else будет не нужен.
> написал свою реализацию DIContainer
Хорошо, советую еще сделать ее совместимой с PSR: https://github.com/container-interop/fig-standards/blob/master/proposed/container.md хотя он пока окончательно не принят.
> всех нужных объектов и данных приведёт к большому куску кода, которому абсолютно нечего делать в index.php и тому подобных скриптах
Делаем либо скрипт container.php, либо класс, либо, что лучше, просто кладем заполнение контейнера в бутстрап-скрипт или класс. Думаю, проще всего не преумнодать сущности и положить все в бустрап-скрипт.
В больших фреймворках вроде Симфони для описания сервисов используется yaml-конфиг, по которому генерируется php код: http://symfony.com/doc/current/components/dependency_injection.html#setting-up-the-container-with-configuration-files
Кстати компонент DI из Симфони можно использовать отдельно от нее.
>>997712
С основ сетевых технологий и обычных сокетов Беркли. У меня были задачи, решишь?
Есть такие задачи: http://arhivach.org/thread/204328/#853691 - если тебе очень не хочется разбираться в особенностях протоколов, первые задачи можно пропустить, но не советую, знания тебе потом пригодятся при отладке программ.
Вот кто-то делал эти задачи (возможно с ошибками): http://arhivach.org/thread/213097/#870803
Вот есть еще пост в старом треде:
https://2ch.hk/pr/res/689537.html#690343 (М)
Есть немного сумбурные вырезки из постов:
https://gist.github.com/codedokode/1af26d3a64748f05ba8b870b273edfc6
https://gist.github.com/codedokode/21a432321fe7bc435dab
https://gist.github.com/codedokode/ffd520440a970c07c1c6
> алсо, какое пастохранилище использовать лучше пастбина?)
gist.github.com если есть гитхаб
> if ( array_key_exists($name, $this->objects) ) {
> $result = $this->objects[$name];
Лучше сразу return, читать будет проще и else будет не нужен.
> написал свою реализацию DIContainer
Хорошо, советую еще сделать ее совместимой с PSR: https://github.com/container-interop/fig-standards/blob/master/proposed/container.md хотя он пока окончательно не принят.
> всех нужных объектов и данных приведёт к большому куску кода, которому абсолютно нечего делать в index.php и тому подобных скриптах
Делаем либо скрипт container.php, либо класс, либо, что лучше, просто кладем заполнение контейнера в бутстрап-скрипт или класс. Думаю, проще всего не преумнодать сущности и положить все в бустрап-скрипт.
В больших фреймворках вроде Симфони для описания сервисов используется yaml-конфиг, по которому генерируется php код: http://symfony.com/doc/current/components/dependency_injection.html#setting-up-the-container-with-configuration-files
Кстати компонент DI из Симфони можно использовать отдельно от нее.
>>997712
С основ сетевых технологий и обычных сокетов Беркли. У меня были задачи, решишь?
Есть такие задачи: http://arhivach.org/thread/204328/#853691 - если тебе очень не хочется разбираться в особенностях протоколов, первые задачи можно пропустить, но не советую, знания тебе потом пригодятся при отладке программ.
Вот кто-то делал эти задачи (возможно с ошибками): http://arhivach.org/thread/213097/#870803
Вот есть еще пост в старом треде:
https://2ch.hk/pr/res/689537.html#690343 (М)
Есть немного сумбурные вырезки из постов:
https://gist.github.com/codedokode/1af26d3a64748f05ba8b870b273edfc6
https://gist.github.com/codedokode/21a432321fe7bc435dab
https://gist.github.com/codedokode/ffd520440a970c07c1c6
>>998902
Сделай например клон мобильной версии гиктаймса (m.geektimes.com) либо роема (m.roem.ru), либо новостного сайтпа вроде медузы, что сможешь. Желательно код оформить в виде темы и/или плагинов и выложить на гитхаб без кода вордпресса, так как зачем нам смотреть код вордпресса?
Верстка у тебя пока кривая, переключалка картинок должна работать в новых браузерах без яваскрипта. Бутстрап ты подключил зря, от него в шаблоне ничего нет и он только вредит и утяжеляет страницу.
Шрифты не как на макете.
В HTML коде куча мусора, например:
> <meta content="" property="og:image" />
И некоторые сомнительные теги:
> <meta content="telephone=no" name="format-detection" />
> based in Jupiter and we would love<br> to turn ideas into
Лучше без br
В исходнике сайта у тебя какой-то подозрительный и явно вредоносный зашифрованный яваскрипт:
> window.a1336404323 = 1
>>997786
Гит управляет файлами, а не папками, чтобы удалить папку, надо удалить все файлы в ней или добавить в гитигнор.
>>997853
Какую хочешь, обычно для картинок это размер и формат, для аудио/видео можно добавить длительность, битрейт, кодеки. Посмотри, что дает getId3 и из этого что-нибудь возьми.
>>998120
Можешь решать задачи из ОП поста про студентов итд. Или ты их уже решил?
>>998298
Покажи написанный код и спроси, что именно непонятно. Также, ты задачу про вклад в банк решил?
>>998902
Сделай например клон мобильной версии гиктаймса (m.geektimes.com) либо роема (m.roem.ru), либо новостного сайтпа вроде медузы, что сможешь. Желательно код оформить в виде темы и/или плагинов и выложить на гитхаб без кода вордпресса, так как зачем нам смотреть код вордпресса?
Верстка у тебя пока кривая, переключалка картинок должна работать в новых браузерах без яваскрипта. Бутстрап ты подключил зря, от него в шаблоне ничего нет и он только вредит и утяжеляет страницу.
Шрифты не как на макете.
В HTML коде куча мусора, например:
> <meta content="" property="og:image" />
И некоторые сомнительные теги:
> <meta content="telephone=no" name="format-detection" />
> based in Jupiter and we would love<br> to turn ideas into
Лучше без br
В исходнике сайта у тебя какой-то подозрительный и явно вредоносный зашифрованный яваскрипт:
> window.a1336404323 = 1
>>997786
Гит управляет файлами, а не папками, чтобы удалить папку, надо удалить все файлы в ней или добавить в гитигнор.
>>997853
Какую хочешь, обычно для картинок это размер и формат, для аудио/видео можно добавить длительность, битрейт, кодеки. Посмотри, что дает getId3 и из этого что-нибудь возьми.
>>998120
Можешь решать задачи из ОП поста про студентов итд. Или ты их уже решил?
>>998298
Покажи написанный код и спроси, что именно непонятно. Также, ты задачу про вклад в банк решил?
> http://ideone.com/tMu8IN кубики
Все верно, только exit тут не нужен так как выполниться может только один из 4 блоков.
>http://ideone.com/xutDDU кредит
Теперь можно удалить проверку что долг меньше нуля, и может быть у тебя получится объединть 2 ветки if (когда долго больше и когда меньше 5000) вместе, так как код в них похожий.
> http://ideone.com/Rvv9TQ рулетка
верно
> http://ideone.com/yvE1x7 leet
Верно
>>999083
Покажи код, напиши, что именно непонятно.
>>999201
> $count=count(${'word' . $x});
Вот это уже неправильно. Если ты хочешь обращаться к переменной по номеру, то нужно сложить эти переменные в массив и обращаться к нему.
>>999278
Нельзя. но если другого варианта нет, то можно после проверки. Также в строку одиночных кавычек переменные не подставляются.
>>999436
Гугл https://www.google.ru/search?q=front+controller&newwindow=1&gbv=1&sei=_IkyWamcD4GyswG1kYGIAg
>>999526
Логи попробуй посмтреть если есть. Также журнал событий Windows.
> http://ideone.com/tMu8IN кубики
Все верно, только exit тут не нужен так как выполниться может только один из 4 блоков.
>http://ideone.com/xutDDU кредит
Теперь можно удалить проверку что долг меньше нуля, и может быть у тебя получится объединть 2 ветки if (когда долго больше и когда меньше 5000) вместе, так как код в них похожий.
> http://ideone.com/Rvv9TQ рулетка
верно
> http://ideone.com/yvE1x7 leet
Верно
>>999083
Покажи код, напиши, что именно непонятно.
>>999201
> $count=count(${'word' . $x});
Вот это уже неправильно. Если ты хочешь обращаться к переменной по номеру, то нужно сложить эти переменные в массив и обращаться к нему.
>>999278
Нельзя. но если другого варианта нет, то можно после проверки. Также в строку одиночных кавычек переменные не подставляются.
>>999436
Гугл https://www.google.ru/search?q=front+controller&newwindow=1&gbv=1&sei=_IkyWamcD4GyswG1kYGIAg
>>999526
Логи попробуй посмтреть если есть. Также журнал событий Windows.
CMS может быть. Но ее не прикрутить, на ней сайт надо с нуля делать.
>>999839
В обычном SQL выражение FROM t1, t2, t3 значит JOIN таблиц. Но в сфинксе это значит поиск по нескольким индексам: http://sphinxsearch.com/docs/current/sphinxql-select.html
>>1000174
> Почему в Сфинксе при добавлении строки, в поле вставляется 0 заместо нужного значения?
Не знаю, но можно подсоединиться к сфинксу и просто выбрать данные через SELECT. Может у тебя поле как числовое создано? Также учти что сфинкс это поисковой движок, а не хранилище, и он хранит только атрибуты, но не хранит сами проиндексированные тексты.
Ну вот у тебя в конфиге
> rt_attr_uint = newname
> uint
Почитай-ка
http://sphinxsearch.com/docs/current/conf-rt-attr-uint.html
http://sphinxsearch.com/docs/current/rt-overview.html
> Ещё, после обновления конфига ничего не меняется.
Э? А почему оно должно меняться? Для обычных индексов надо заново запустить индексацию. Это индексер ведь выкачивает данные из базы и создает/обновляет индексы. Для RT-индексов надо дропнуть их и пересоздать заново наверно. Или может демон перезапустить.
Поищи тут
http://sphinxsearch.com/forum/view.html?id=12440
http://sphinxsearch.com/forum/view.html?id=9032
запрос "sphinx alter rt index"
> И после перезагрузки ещё постоянно удаляется папка /var/run/sphinxsearch
Возможно что /var/run очищается при перезагрузке. Можно создавать pid прямо в ней.
> Как определить rt_field и rt_attr_uint, если нужен поиск только по одной колонке?
Надо изучить в чем различие между полями и атрибутами. Поля используются только для индексирования текста в них и не сохраняются. Атрибуты не добавляют текст в индекс, но сохраняются и их можно использовать в условии WHERE.
http://sphinxsearch.com/wiki/doku.php?id=fields_and_attributes
http://sphinxsearch.com/docs/current.html#attributes
http://sphinxsearch.com/docs/current.html#conf-rt-field
> Ещё, при индексации я получаю сообщение "Skipping non-plain index 'rt'...",
Не знаю, что это значит. Ты можешь попробовать включить в конфиге или опцией командной строки режим более подробного вывода логов (verbose или как-то так) и поискать причину там.
>>1000257
Я думаю, docs[0] значит число документов, содержащих первое поисковое слово keyword[0]. Поиск ведь ведется так, что для каждого слова в индексе ищутся id документов, а потом эти списки id объединяются в соответствии с текстом запроса (тут немного упомянуто: https://habrahabr.ru/post/263823/ http://www.pvsm.ru/java/24146 ).
Число результатов - это total.
CMS может быть. Но ее не прикрутить, на ней сайт надо с нуля делать.
>>999839
В обычном SQL выражение FROM t1, t2, t3 значит JOIN таблиц. Но в сфинксе это значит поиск по нескольким индексам: http://sphinxsearch.com/docs/current/sphinxql-select.html
>>1000174
> Почему в Сфинксе при добавлении строки, в поле вставляется 0 заместо нужного значения?
Не знаю, но можно подсоединиться к сфинксу и просто выбрать данные через SELECT. Может у тебя поле как числовое создано? Также учти что сфинкс это поисковой движок, а не хранилище, и он хранит только атрибуты, но не хранит сами проиндексированные тексты.
Ну вот у тебя в конфиге
> rt_attr_uint = newname
> uint
Почитай-ка
http://sphinxsearch.com/docs/current/conf-rt-attr-uint.html
http://sphinxsearch.com/docs/current/rt-overview.html
> Ещё, после обновления конфига ничего не меняется.
Э? А почему оно должно меняться? Для обычных индексов надо заново запустить индексацию. Это индексер ведь выкачивает данные из базы и создает/обновляет индексы. Для RT-индексов надо дропнуть их и пересоздать заново наверно. Или может демон перезапустить.
Поищи тут
http://sphinxsearch.com/forum/view.html?id=12440
http://sphinxsearch.com/forum/view.html?id=9032
запрос "sphinx alter rt index"
> И после перезагрузки ещё постоянно удаляется папка /var/run/sphinxsearch
Возможно что /var/run очищается при перезагрузке. Можно создавать pid прямо в ней.
> Как определить rt_field и rt_attr_uint, если нужен поиск только по одной колонке?
Надо изучить в чем различие между полями и атрибутами. Поля используются только для индексирования текста в них и не сохраняются. Атрибуты не добавляют текст в индекс, но сохраняются и их можно использовать в условии WHERE.
http://sphinxsearch.com/wiki/doku.php?id=fields_and_attributes
http://sphinxsearch.com/docs/current.html#attributes
http://sphinxsearch.com/docs/current.html#conf-rt-field
> Ещё, при индексации я получаю сообщение "Skipping non-plain index 'rt'...",
Не знаю, что это значит. Ты можешь попробовать включить в конфиге или опцией командной строки режим более подробного вывода логов (verbose или как-то так) и поискать причину там.
>>1000257
Я думаю, docs[0] значит число документов, содержащих первое поисковое слово keyword[0]. Поиск ведь ведется так, что для каждого слова в индексе ищутся id документов, а потом эти списки id объединяются в соответствии с текстом запроса (тут немного упомянуто: https://habrahabr.ru/post/263823/ http://www.pvsm.ru/java/24146 ).
Число результатов - это total.
Потому что это тематика сайта. Хуй знает что ты имеешь ввиду.
$app->get('/{fileId}[/{wrongFields:.*}]', function ($request, $response, $args) {
$wrongFields = explode('/',$request>getAttribute('wrongFields'));
});
Количество неправильных полей неограничено, переданные таким образом значения закинутся в массив ($errors[] = $calue), а затем в шаблоне я укажу пользователю неправильные поля. Но таким образом не будет расшифровки ошибок из-за формата роута.
В случае с вариантом POST меня смущает создание дополнительного шаблона с данным методом. Т.е. в конце метода addCommentAction будет...
$this->view->render($response, "just_another_form.twig", [
"wrongField1" => "some desc",
"wrongField3 => "blah error blah"
]);
Ну вот, может есть еще альтернатива? Первый раз работаю с MVC и путаюсь, студентов писал на ООП. Все это на Slim и Twig, если что.
>p->get('/{fileId}[/{wrongFields:.*}]', function ($request, $response, $args) {
Перекат
https://2ch.hk/pr/res/1000416.htm (М)
1. Есть ли смысл НЕ закрывать одиночные теги? Типа <br />
2. Какой вообще смысл использовать method="get" вместо post?
3. Кто-нибудь вообще использует <code> <kbd> <samp> <var> <pre> ?
4.Посмотрел отличия XHTML от HTML, так и не понял: когда на практике используют XHTML?
>1. Есть ли смысл НЕ закрывать одиночные теги? Типа <br />
Зачем ставить слеш? Кажется в XHTML никто не будет вкатываться, HTML5 подъехал.
2. Какой вообще смысл использовать method="get" вместо post?
Это для серверной части. Гет используется для передачи параметров в адресной строке, тупо текстом(потом эти параметры разбираются в каком-нибудь фронт-контроллере), Пост - для передачи параметров в суперглобальный массив $_POST, сразу на сервер, иногда нужно передавать в гет, иногда в пост.
3. 3. Кто-нибудь вообще использует <code> <kbd> <samp> <var> <pre> ?
хуй знает, я специально вообще хтмл не учил, по мере необходимости гуглю нужные теги, использую <pre> в php, что бы в тестах выводимые данные отображались прилично, а не сплошным текстом, в гугле есть точное описание каждого тега.
>4.Посмотрел отличия XHTML от HTML, так и не понял: когда на практике используют XHTML?
Настолько я понял XHTML пришёл на замену HTML, но внезапно(нет) выкатили HTML5 и все радостно на него перекатились, а про XHTML забыли.
Если я хуйню понаписал - поправьте, сам ньюфаг.
Это копия, сохраненная 14 июня 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.