Это копия, сохраненная 11 августа 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Предыдущий тред был тут: >>1000416 (OP) ( http://arhivach.org/thread/266631/ ). Еще предыдущие треды ищутся в гугле по словам "клуб php" или в архиваче. Еще есть такой архив тредов: 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 3/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.
Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:
https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md
Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md
Решения задач лучше показать мне, особенно на ООП,так как сам ты вряд ли увидишь все ошибки. Пости свой код на гитхаб и вкидывай ссылку в тред по мере решения. Я прокомментирую и укажу на ошибки.
Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.
- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://github.com/codedokode/pasta/blob/master/db/databases.md
Что почитать
- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.
Платиновые вопросы
- Почему PHP? Потому что фейсбук и википедия на нем написаны, и вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery. У нас в треде были люди, которые практически с нуля учились и смогли найти работу.
- Что будут спрашивать на собеседовании если 0 опыта - гонять по теории, по официальному мануалу PHP, давать дурацкие задачки на переворачивание строк, гонять по SQL (транзакции, внешние ключи, напиши запрос), по JS (как сделать анимацию при нажатии кнопки), ну погугли, не ленись
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/.
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Посоветуйте редактор кода - 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, то рассказать об этом стоит в каком-нибудь другом треде.
Не придирайся к знанию английского языка, анон пишет как умеет.
Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
Этот проект https://github.com/Merkalov/Students я проверил тут >>1005550 (если тред утонул, ищите в архиваче)
Юзаю codelobster. Пытался в netbeans, но во-первых: он тоже притормаивает, а во вторых - нет нормального автодополнения для laravel и blade.
Может кто-то посоветовать, что-то годной для старых компухтеров?
Я имею в виду, есть ли проекты, требующие навыков написания кода на обоих этих языках. И насколько это экзотика?
хайлоад (хотя сейчас там чаще посматривают в сторону Го или Раста, но их без знания Си изучать трудно).
сублайм терпеть не могу. Уж сорян, пытался его настроить даже поюзал какое-то время, но отсутствие тулбара, настройки через пизду, все на горячих клавишах, отсутствие проводника и самое главное черный цвет паталогически не могу кодить в темных редакторах заставили меня его снести, уж лучше codelobster. Может еще какие варики есть?
>нет нормального автодополнения для laravel и blade
https://www.google.ru/search?q=netbeans+blade+syntax+highlighting&gws_rd=cr&ei=jEFiWaPzFcbC6QTpvrqoCA
Жёсткий диск заменил на ССД?
Ты конкретную ссылку дай, то, что ты умеешь запрос в гугле составить я понял. Есть полурабочие способы, где нужно плясать с бубном - это никак не подходит под определение "норальное"
Для блейда есть плагин, емнип
А почему тогда не сделаны сеттеры на ранг или на лидера?
И получается нужно на все вводимые данные делать сеттеры и на сеттеры ставить тайпхинты? А на все другие данные константы?
Есть миллион готовых библиотек для иконок.
Если заказчик дает тебе эскиз (макет), то иконки все есть.
Если в студии с кем-то, то также - картинки даны.
Верстальщику рисовать не очень нужно.
>
- сделать для каждой формы свой URL, который и выводит ее (при GET), и обрабатывает запрос (при POST). И форма с главной шлет запрос на этот URL, при ошибке выводится только сама форма с ошибкой.
Не понял. Допустим обработался некоторый не-главный-экшн, который работает с формой, допустим комментария...
> При ошибке выводится только сама форма с ошибкой
...это что, будет вью только с этой формой комментария? Т.е. шаблон без ничего (ну кроме шапки и подвала, которые везде инклюдятся), только эта форма?
Или же, если я правильно понял, эти две формы выводятся и в local.app/controller/indexAction и в local.app/controller/someAction, но как второй экшн вернет главному список ошибок? Можно немного псевдокода, что-то я давно мучаюсь с этими второстепенными экшнами и мой код сейчас выглядит как пикрелейтед (функции delFile, addComment, checkAccessPass являются не экшнами, а просто уменьшают толщину контроллера).
Тебе надо работать с БД, в которой ты будешь хранить юзеров и данные.
Для авторизации пользователя тебе надо куки.
Загрузка файлов - обычная работа с файлами, вида
...
<form enctype="multipart/form-data" action="addres" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="44444" />
<input name="userfile" type="file" />
<p><input type="submit" value="Загрузить"></p>
</form>
...
$uploaddir = 'dir';
$uploadfile=$uploaddir.basename($_FILES['userfile']['name']);
...
почему везде все это дается кусками и приходить потом дрочить что бы все это собрать в одно?
Давно смотрел видосы от этого васяна: https://school-php.com/video
Они всратые, старые, в них много воды и они примитивные, но после них я научился строить какую-никакую архитектуру сайта, понял как делаются все эти авторизации и пр. Рекомендую их только потому, что не знаю смог бы я научится всему тому, по следующим урокам...
... а это уроки для илиты, это реально ахуенная хуйня, тут есть все: от самых основ (переменные, массивы, циклы и пр.) до ООП, паттернов, MVC, обзора по фреймворкам и т.пр. Качество плоховатое, но я реально ничего лучше не видел, просто посмотри на программу Кликни на "дополнительная информация" каждого из уроков:
1 уровень: http://nnm-club.me/forum/viewtopic.php?t=889322
2 уровень: http://nnm-club.me/forum/viewtopic.php?t=889427
3 уровень: http://nnm-club.me/forum/viewtopic.php?t=889601
4 уровень: http://nnm-club.me/forum/viewtopic.php?t=1014639
Спасибо.
Только полгода назад сделал поделку на ларавел, а сейчас как будто и не делал ничего, всё заново учу.
А вы что творите, аноны?
И вообще, есть тут те, кто работает пхп джуном? Что вы вообще делаете?
ты так все время пердолишь окно?
и в фф и в хромиум-* вроде же есть эмуляция
и почему шиндовс?
По всякому. Бывают собеседования, где за каждую строчку пояснить просят.
сайт pisos.ru
как сделать, чтобы файл
/folderWithCandies/dick.html
открывался по адресу pisos.ru/dick ?
через редирект 301 или что-то типа того
Какая эмуляция?
На мак денег пока нет. А в лиуксе интерфейс громоздкий, сжирает много экранного места по вертикали, и безбожно томозит, всё это в сравнении с виндой. Хостинг - выделенный на убунте, пердолю через ssh, гуй там не нужен.
Вчера открыл для себя, что вместо копирвоания файлов на хостинг через ftp или ssh можно просто сделать там пулл реквести из гит.
>/folderWithCandies/
На выделенном хостинге настроить апач или нгникс так чтобы корневой папкой была "/folderWithCandies/"
На виртуальном можно создать в корне dick.php который будет подтягивать "/folderWithCandies/dick.html" с помощью require или include. В адресной строке тогда останется "pisos.ru/dick"
htaccess может только перенаправить с "pisos.ru/dick" на "/folderWithCandies/dick.html" В адресной строке тогда будет "/folderWithCandies/dick.html" и ничего с этим не поделать
А вообще обязательно описывай зачем, может тебе вообще что-то другое пододёт
> Нужно для каждого статуса для заданного диапазона дат получить кол-во транзакций с данным статусом,
Группировка не годится? Только таблицу повернуть, чтобы были такие колонки
date | ok | wait | cancel
------------------------
> Непонятно только что нужно знать на практике. Уже несколько раз видел сервисы амазона в списке требований в вакансиях, поэтому интересуюсь.
Лучше всего у них было и спросить. но Линукс конечно знать нужно для работы с виртуалками.
> Чо они вагрантом не пользуются
Судя по документации, вагрант - это средство для настройки виртуальных машин. В том числе и созданных в облаке амазона. Так что твою мысль я плохо понимаю. Они тебе им пользоваться не запрещают, а им самим он никак не нужен и ничем не поможет.
Там ведь разные сервисы, хранилища файлов, базы данных, и тд.
Тебе действительно стоило бы разобраться, что именно у них есть. В случае с EC2 Амазон просто предоставляет тебе виртуальную машину и ты с ней уже делаешь, что хочешь. В том числе и с помощью вагранта.
> То есть persist на каждом шагу и не нужен.
persist используется для передачи новых созданных объектов под управление entity manager. На каждом шагу он не нужен, да.
> В этом и состоит суть паттерна, что изменения в сущностях отслеживаются автоматически и сохраняются в базу при коммите?
Вроде примерно это (судя по https://martinfowler.com/eaaCatalog/unitOfWork.html ). Но там написано, что главное преимущество UOW это запись изменений атомарно, одной транзакцией, а не кучей мелких транзакций.
Доктрина содержит в UOW ссылки на все управляемый ей сущности (загруженные из БД, а также добавленные через persist), а также их исходное состояние и при flush() сравнивает их текущее состояние с исходным, находит различия, формирует пакет изменений и сбрасывает эти изменения в базу одной транзакцией.
То есть она экономит силы разработчика на определение этих изменений и написание запросов вручную, это заметно, когда ты делаешь много изменений и когда у сущностей много связей.
> Ну то есть в классе UOW имеется маппер и репозиторий для каждой сущности,
Нету там ни мапперов, ни репозиториев.
Условно говоря, UOW это идея, что изменения надо накапливать и сбрасывать одной транзакцией, а не делать запрос в тот момент, когда изменяется сущность.
> Ну то есть в классе UOW имеется маппер и репозиторий для каждой сущности,
Нет там внутри никаких мапперов, просто там есть массив сущностей и массив с их исходным состоянием (значениями полей). Это легко увидеть, если посмотреть код.
> при извлечении из бд в репозиторий
В репозитории ничего не хранится.
> сохраняется ссылка на модель с статусом типа "clean", когда мы меняем свойства модели через сеттер, статус меняется на "dirty"
Нет. По умолчанию при загрузке из БД Доктрина просто сохраняет значения полей и ссылку на объект, а при flush() сравнивает текущее состояние объекта с исходным. Но ты можешь использовать и другие опции, например сделать объекты, которые будут сами сообщать в доктрину об изменениях, чтобы сэкономить время на поиск изменений (но это усложняет сущности). То есть возможны варианты когда объекты сообщают об изменениях, и когда Доктрина сама их ищет, это настраивается.
Также, если тебе интересно, Доктрина не использует геттеры/сеттеры, а получает доступ к приватным свойствам с помощью reflection. Потому ты можешь не делать геттеры или сеттеры, если логика подразумевает что поле нельзя менять или читать снаружи. Или ты можешь например при изменении одного поля менять второе, то есть пишешь любую логику, какую хочешь.
> Я придумал новую интеллектуальную игру
Тут можно использовать метод деления пополам, чтобы найти прблемное слово за относительно небольшое число постов. Делим пост на 2 равные части, определяем в какой проблема, делим проблемную часть еще на 2, и так далее.
> Нужно для каждого статуса для заданного диапазона дат получить кол-во транзакций с данным статусом,
Группировка не годится? Только таблицу повернуть, чтобы были такие колонки
date | ok | wait | cancel
------------------------
> Непонятно только что нужно знать на практике. Уже несколько раз видел сервисы амазона в списке требований в вакансиях, поэтому интересуюсь.
Лучше всего у них было и спросить. но Линукс конечно знать нужно для работы с виртуалками.
> Чо они вагрантом не пользуются
Судя по документации, вагрант - это средство для настройки виртуальных машин. В том числе и созданных в облаке амазона. Так что твою мысль я плохо понимаю. Они тебе им пользоваться не запрещают, а им самим он никак не нужен и ничем не поможет.
Там ведь разные сервисы, хранилища файлов, базы данных, и тд.
Тебе действительно стоило бы разобраться, что именно у них есть. В случае с EC2 Амазон просто предоставляет тебе виртуальную машину и ты с ней уже делаешь, что хочешь. В том числе и с помощью вагранта.
> То есть persist на каждом шагу и не нужен.
persist используется для передачи новых созданных объектов под управление entity manager. На каждом шагу он не нужен, да.
> В этом и состоит суть паттерна, что изменения в сущностях отслеживаются автоматически и сохраняются в базу при коммите?
Вроде примерно это (судя по https://martinfowler.com/eaaCatalog/unitOfWork.html ). Но там написано, что главное преимущество UOW это запись изменений атомарно, одной транзакцией, а не кучей мелких транзакций.
Доктрина содержит в UOW ссылки на все управляемый ей сущности (загруженные из БД, а также добавленные через persist), а также их исходное состояние и при flush() сравнивает их текущее состояние с исходным, находит различия, формирует пакет изменений и сбрасывает эти изменения в базу одной транзакцией.
То есть она экономит силы разработчика на определение этих изменений и написание запросов вручную, это заметно, когда ты делаешь много изменений и когда у сущностей много связей.
> Ну то есть в классе UOW имеется маппер и репозиторий для каждой сущности,
Нету там ни мапперов, ни репозиториев.
Условно говоря, UOW это идея, что изменения надо накапливать и сбрасывать одной транзакцией, а не делать запрос в тот момент, когда изменяется сущность.
> Ну то есть в классе UOW имеется маппер и репозиторий для каждой сущности,
Нет там внутри никаких мапперов, просто там есть массив сущностей и массив с их исходным состоянием (значениями полей). Это легко увидеть, если посмотреть код.
> при извлечении из бд в репозиторий
В репозитории ничего не хранится.
> сохраняется ссылка на модель с статусом типа "clean", когда мы меняем свойства модели через сеттер, статус меняется на "dirty"
Нет. По умолчанию при загрузке из БД Доктрина просто сохраняет значения полей и ссылку на объект, а при flush() сравнивает текущее состояние объекта с исходным. Но ты можешь использовать и другие опции, например сделать объекты, которые будут сами сообщать в доктрину об изменениях, чтобы сэкономить время на поиск изменений (но это усложняет сущности). То есть возможны варианты когда объекты сообщают об изменениях, и когда Доктрина сама их ищет, это настраивается.
Также, если тебе интересно, Доктрина не использует геттеры/сеттеры, а получает доступ к приватным свойствам с помощью reflection. Потому ты можешь не делать геттеры или сеттеры, если логика подразумевает что поле нельзя менять или читать снаружи. Или ты можешь например при изменении одного поля менять второе, то есть пишешь любую логику, какую хочешь.
> Я придумал новую интеллектуальную игру
Тут можно использовать метод деления пополам, чтобы найти прблемное слово за относительно небольшое число постов. Делим пост на 2 равные части, определяем в какой проблема, делим проблемную часть еще на 2, и так далее.
Как закрыть папку, чтобы извне никто не мог смотреть/исполнять файлыы, а сам сервер мог к ним оборащаться?
Экспериментировал с такими конструкциями и либо не блокируется ничего, либо блокируется для всех:
<FilesMatch ".(htaccess|php|jpg)$">
Order Allow,Deny
Deny from all
</FilesMatch>
Order deny,allow
Deny from all
<Files ~ ".(xml|css|jpe?g|php)$">
Allow from all
</Files>
>отсутствие проводника
Open folder побывал ?
>черный цвет
white theme sublime text в гугл
>все на горячих клавишах
разве в шторме не тоже самое ?
>настройки через пизду
кто то не может в json объекты ?
не говорю что он пизже всех или замена IDE но имхо для моих задач хватает с головой и не жрёт 1000 ГБ рама , Atom есть , Brackets но они все чёрные , что при желании можно легко изменить
Зачем тулбар? Я наоборот рад, что в нем нет этих дурацких кнопок. Цвет меняется, я сам не могу читать на темном фоне, тем более на моей плохой матрице. Файлы открываются через Ctrl + P либо через Ctrl + O с вписыванием пути вручную (в Windows в диалоге открытия файла можно писать путь и он дополняется).
Плагинами лучше не увлекаться, так как какой-нибудь из них рано или поздно начнет все замедлять.
Нашел
https://pastebin.com/8NkvceWp
Я не пхпшник, но разве buy->name не должно возвращать значение, например, с помощью return, как в других ЯП?
сорян, я constructor пишу, а надо construct
ОП, смотри на что наткнулся по пыхе и по ноде нашел такое же
https://phpschool.io/
Есть идея твои уроки перепилить в формат подачи воркшопов. Стоит ли?
хочу сокращатель ссылок сделать
только теперь еще больше запутался и не пойму как это сделать нормально
Тебе нужно динамически генерировать html с помощью php. Пользователь вводит адрес, ты проверяешь есть ли такой в базе, если есть даешь ему короткую ссылку из базы, если нет генерируешь короткую ссылку и кладешь в базу.
Не обязательно.
Используй фреймворки. Попробуй Slim, он простой.
ставлю коробку под ларавел, запускаю виртуалку, но проблема - не установлен в ней mcrypt. захожу по ssh, устанавливаю через apt php7.1-mcrypt и хуяк! все ломается, все к едрени бабушки перекосоебливается и не работает. Версия php на виртуалке 7.1
>Вчера открыл для себя, что вместо копирвоания файлов на хостинг через ftp или ssh можно просто сделать там пулл реквести из гит.
Да пребудет с тобой git clone.
И второй вопрос, можно ли спуфить IP курлом при запросе из cli с параметром interface с учетом что использованный IP куплен и установлен на сервере тоже
Как правильно использовать php. Писать html в php коде, или php код в html странице? Или может как то еще можно?
Если что-то простое, то юзать PageController, если посерьезнее - FrontController и ApplicatiobController
я у мамы зандстраёб
Спасибо. Щас по гуглю.
Ответь еще пожалуйста, в php есть встроенные обработчики, ну как в ноде например, пишешь обработчик для запроса и вызываешь функцию? Не смог нагуглить точный ответ.
И еще кое что, как делают так, что при запросе www.host.ru/page открывается страница без окончания index.php? Знаю что во фреймворках такое, но как сделать без фреймворков не могу нагуглить.
Тайпхинты не использовал, смысл в них вообще.
А еще ошибки не знаю как исправить.
Тайпхинты для правильно DI же , что бы ты точно знал что тебе передаётся именно тот объект
либо ajax либо POST GET с перезагрузкой страницы , то есть отсылаешь все данные с формы на какой то скрипт обрабатываешь и получаешь результат
Как я понял апач будет переадресовывать на файлы, какждый файл это хост? Чет костыль какой то получается. Может у меня нжинкс будет.
Может кто-нибудь знает как нормально сделать, что при запросе отрабатывала функция? Хотя бы в теории как это в php, какие есть функции и структуры для этого.
Не понятно. Вот открыл юзер в браузере www.host.ru/page, предположим это главная страница, значит GET запрос, как этот запрос обработать?
Не пойму зачем мне форма, если нужно гет запросы обрабатывать.
https://ideone.com/FWNxh4
а в этом смысле www.host.ru/page пофакту должно быть www.host.ru/page.php но всякие мод реврайты умеют обрезать эту .php или например www.host.ru/index.php/page тоже умеют обрезать index.php
скрипт выполняется скрипт из этого самого page.php
так то да , по нормальному у тебя должен быть всего 1 входная точка это index.php и она обработает запрос на тот же page но тогда гугли простейшие route pattern
RewriteEngine on
RewriteRule page page.php
RewriteRule vasya/pupkin/khuy/zalupkin user.php?id=1488
Там много есть почитать.
https://habrahabr.ru/company/sprinthost/blog/129560/
http://htaccess.ru/
Мне лично вот этот помог разобраться на примерах:
http://ruseller.com/lessons.php?id=1916
Кто нибудь может объяснить что не так с php. Можно ли как в ноде или в других языках запустить php файл на выполнение и чтобы он обрабатывал все запросы? Если я правильно понял, то нельзя, из-за того что php отрабатывает код файла и умирает.
Спасибо анон. Просто я хожу разобраться с тем как работает интерпретатор php, и как устроена работа с http. Не хочу ставить апач. Мне не горит решать это, мне нужно понять как работает сам php. Похоже в строке запроса php может получать только параметры после знака ?, это вообще печаль, как жить то???
### Тайп хинты
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ (увы, возможность вернуть null пока не реализовали, так что ждем)
Здесь нет нужной информации? http://php.net/manual/ru/reserved.variables.server.php
Когда приходит HTTP запрос, PHP анализирует его и кладет информацию о нем в суперглобальные переменные $_SERVER, $_GET, $_POST, $_COOKIE, $_FILES, $_ENV - они описаны в документации.
Все, что выводит программа (echo и подобными функциями), PHP отправляет в теле HTTP ответа.
На заголовки HTTP ответа можно повлиять с помощью функций header, set_cookie и некоторых ini-настроек.
Да, можно, ты можешь самостоятельно слушать порт (создав пассивный сокет), принимать HTTP запросы, разбирать их и обрабатывать много запросов подряд, не умирая.
Проще всего делать это по очереди, но если очень хочется, то возможна и асинхронная параллельная работа с помощью библиотек вроде ReactPHP.
С PHP все в порядке.
>>1020876
Непонятно, в чем суть вопроса. Создаешь PHP файл и обрабатываешь.
>>1020911
Формы тут не при чем. Если тебе не нужны красивые URL то просто создаешь файлы index.php, page.php и так далее. Если нужны, то перенаправляешь настройками веб-сервера все запросы на index.php и в нем уже анализируешь URL и вызываешь нужный обработчик.
Вообще-то у меня это описано в уроке для встроенного в PHP сервера, почему не прочел? https://github.com/codedokode/pasta/blob/master/soft/web-server.md
Ссылка в ОП посте стоит.
PHP Fatal error: Uncaught Error: Call to undefined function mb_internal_encoding() in /home/hIt56v/prog.php:5
Везде, даже в самых простых вещах вылезает эта лажа на ideone. Я косячу или такова воля Божья?
Все mb_* это дополнительная, не обязательная библиотека, видно на ideone она не установлена , оттуда и проблемы.
http://php.net/manual/en/book.mbstring.php
SELECT
`iblock_element`.`ID` AS `ID`
FROM `b_iblock_element` `iblock_element`
LEFT JOIN `b_iblock_element_property` `iblock_element_property` ON `iblock_element_property`.`IBLOCK_ELEMENT_ID` = `iblock_element`.`ID`
WHERE (`iblock_element_property`.`VALUE` = '423') AND (`iblock_element_property`.`VALUE` = '408')
неужели так? а если у меня пиздец сложная логика на каждое значение по джоину?
SELECT
`iblock_element`.`ID` AS `ID`
FROM `b_iblock_element` `iblock_element`
LEFT JOIN `b_iblock_element_property` `iblock_element_property` ON `iblock_element_property`.`IBLOCK_ELEMENT_ID` = `iblock_element`.`ID`
LEFT JOIN `b_iblock_element_property` `iblock_element_property2` ON `iblock_element_property2`.`IBLOCK_ELEMENT_ID` = `iblock_element`.`ID`
WHERE (`iblock_element_property`.`VALUE` = '423' AND `iblock_element_property2`.`VALUE` = '408')
Какой-то код это обычно всегда плюс, особенно если он хороший. Это дает возможность более адекватно оценить навыки кандидата.
> И вообще, есть тут те, кто работает пхп джуном? Что вы вообще делаете?
Бэкэнд часть я делаю.
пхп-джун
>>1020945
В PHP 7.1 есть возвращаемый тип void: https://3v4l.org/0kuHL
>>1020973
https://3v4l.org/
>>1020914
Можешь объяснить, чем плохи чистые функции, зачем городить эти Utility service? Юнит-тесты ты ведь всё равно писать не будешь. Какое-то слепое следование паттернам ради усложнений.
>>1020834
Хороший вопрос, тут есть ответ: http://www.php.su/articles/?cat=examples&page=014
>>1020857
Эти паттерны не отвечают на вопрос как увязывать HTML и PHP.
Изменение номера - https://ideone.com/KJxmSg
Автозамена - https://ideone.com/LaOqC8
Вывод email - https://ideone.com/NCD54g
Grammar Nazi - https://ideone.com/BR95EM
Мне казалось, всякий код должен быть на своем месте. Что если мне понадобится вот этот rand() в любом месте кода, я позову его из сервиса и всё.
Предлагаешь лучше просто собрать их все в файл и подключать прямо к window?
стайлгайд http://www.sqlstyle.guide/ru/
Инфа от ОПа https://github.com/codedokode/pasta/blob/master/db/databases.md
https://youtu.be/REbsxmE5h4M проектирование базы в MySQL Workbench
>Open folder побывал ?
Что это? Папка как проект? Мне нужен проводник по всей системе - в notepad++, например, он сделан идеально.
>разве в шторме не тоже самое ?
я его не юзал толком, но там вроде есть возможность влепить тулбар
>кто то не может в json объекты ?
а че ты в дефолтном виндовом блокноте не кодишь? Не можешь в него?
>>1020370
>Я наоборот рад, что в нем нет этих дурацких кнопок
только выиграл от отсутствия того, что всегда можно отключить?
Последнее время, перед собеседованием просят показать небольшой файл с примером кода.
Я хочу отправлять это: https://pastebin.com/F9Cv1eXm
Рейт ми, как говорится. Может чего подправить стоит?
>а че ты в дефолтном виндовом блокноте не кодишь? Не можешь в него?
м манёвры ? сравнить json объекты с кучей формочек ? имхо мне даже удобнее поправить в файле нежели бегать по файл -> правка -> опция залупки
Это просто дело вкуса, я думаю. Кто-то любит кнопочки, кто-то конфиги. У конфигов в сравнении с GUI масса преимуществ - ими можно делиться, публиковать, бекапить, делать поиск, генерировать программно, но из минусов - нужно сначала потратить время на изучение.
Если программа рассчитана на разработчиков, а не на "обычных" пользователей, вполне логично использовать текстовый конфиг.
Некоторые редакторы пытаются взять лучшее из обоих миров - давая и GUI и конфиг в XML, вроде eclipse, но по моим ощущениям, настройки у них совсем уж навороченные.
>Бэкэнд часть я делаю
это понятно, хотелось бы подробней. Прямо со старту ты пришел джуном и на тебя весь бэкэнд свалили?
Я поработал над указанными ошибками, но исправил не все.
Во-первых, что исправил:
>Советую убрать опцию переименования таблиц через конфиг, это требует много усилий, а выгода неочевидна.
Убрал из конфига, в PDO обращаюсь к таблицам по имени. Теперь их названия прибиты гвоздями. Не уверен, что это лучше, но сделал.
>Советую убрать реальные даты, названия компаний, номера и фамилии из скриншота, заменить на вымышленные.
Убрал
>Тут код отформатирован ужасно: https://github.com/tsubaku/flights/blob/master/submit.php
Переформатировал. Теперь правильно? Перевёл в camelCase названия пхп-функций. Переменные не переводил, их слишком много.
>Если ты отдаешь JSON, то тип ответа должен быть application/json, не надо изобретать свои стандарты. И логично заголовки ставить не в начале скрипта, а перед отдачей самого JSON
Заменил text/plain на application/json везде, где возвращается JSON. Перенёс хидеры к echo json_encode. Нужны ли хидеры там, где только echo? А там, где вообще ничего нет, просто вызов функции?
> $pass = md5(md5(trim($pass)));
>Безопаснее использовать соленый хеш, как описано в моем уроке https://github.com/codedokode/pasta/blob/master/security/password-hashing.md
Заменил md5 на password_hash/password_verify
>При загрузке картинок нет проверки типа файла, человек загрузит .png или .txt, а ты его переименуешь в .jpg например.
Сделал проверку и корректное расширение для jpg, png, gif, остальным типам скрипт отказывает в загрузке.
> https://github.com/tsubaku/flights/blob/master/show_list_clients.php#L10
> while(list ($key, $val) = each ($_POST)){
>Это давно устарело, нужно использовать foreach тут
Переделал
>Название функции должно начинаться с глагола, то есть не protection, а redirectIfNoPrivileges(...)
Заменил на verifyAuthorization
> <a href='#' class='a_button_delete'
Ссылка должна куда-то вести. Для создания кнопки есть тег button.
Оформил в виде button. Немного поехала вёрстка кнопки, потом поправить.
> while ($i <= count($ru_rows_array)-1){
Тут нужно использовать foreach. Ты сишник наверно? Не надо тянуть плохие практики из Си в язык, где есть foreach.
Заменил в нескольких местах count на foreach
> if (is_null($_COOKIE['id'])
Это неправильно и вызовет ошибку, если в массиве нет ключа 'id'. У тебя наверно включено игнорирование предупреждений, или же ты не смотришь в логи ошибок, раз этого не видишь. Нужно использовать array_key_exists или isset здесь.
Хм, никаких ошибок в логах. Хотя, может быть я просто проверил не все случаи. Заменил is_null на empty.
https://github.com/tsubaku/flights/blob/master/functions.php#L187
> $info = getimagesize($path);
>Тут не проверяется вариант, когда функция вернет вместо массива false.
Добавил проверку
Что исправил с оговорками:
>В шаблонах у тебя вроде бы есть повторяющиеся куски - шапка страницы.
Шапки немного повторяются, но всё же есть различия и не думаю, что сливать общие части имеет смысл. Плюс, так их легче воспринимать. Я разделил скрипт core.js, вынеся в отдельные файлы скрипты менеджера и охранника, а в шаблонах убрал загрузку лишних скриптов.
>https://github.com/tsubaku/flights/blob/master/index.php#L10
> if ($user_level == 9) {
>Тут нужно ииспользовать константу с понятным названием вместо цифры
> $level = 'manager';
>И тот тоже желательно константу.
Немного переписал функцию проверки, теперь она возвращает ид, уровень доступа и фамилию. Проверку оставил по тому же условию.
> echo "<br />";
В HTML слеш в конце тега не ставится, в отличие от XML/XHTML.
Так у меня как раз XHTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
> https://github.com/tsubaku/flights/blob/master/functions.php#L292
> header("Location: status_codes.php?result=403");
Если ты хочешь отдать код ответа HTTP, то надо его отдавать сразу. Потому что редирект - это код вроде 302. То есть ты вместо отдачи кода 403 отдаешь код 302 в ответ на запрос. И вместо "доступ запрещен" говоришь "страница переехала на другой адрес".
Я так и не понял, как сделать так, чтобы браузер при ошибках показывал суть ошибки. Ну или хотя бы стандартные коды. Так что просто заменил все редиректы на header("Location: login.php");
Что не удалось:
>Выделить публичную папку (т.е. папку для файлов, которые можно запросить снаружи) отдельно. Сейчас у тебя по сути все лежит в публичной папке веб-сервера, что небезопасно. Например, можно скачать шаблоны и увидеть их исходный код, а также скачать конфиг.
Выделил папку core, в неё перенёс все НЕ публичные пхп, шаблоны и закачиваемые фотографии. Но как закрыть её, не понимаю. .httaccess полностью рубит доступ и скрипты просто не работают. Как сделать так, чтобы сервер обращаться к ним мог, а левый юзер нет, я не нашёл информации.
>Тут https://github.com/tsubaku/flights/blob/master/show_list_clients.php в одном файле смешана логика и вывод данных в HTML, почитай про шаблоны http://web.archive.org/web/20161119062218/www.phpinfo.su/articles/practice/shablony_v_php.html
Немного переписал и упростил вывод таблиц охранников и клиентов, но как их шаблонизировать, я не знаю (статью читал). Данные в ячейки подставляются в цикле, имена ячеек тоже. При шаблонизации для каждой ячейки придётся писать отдельный вызов, получится монструозно.
>https://github.com/tsubaku/flights/blob/master/functions.php#L5
>Тут слишком сложная функция с слишком большой глубиной отступов
Да, функция монструозная. Я не знаю, как её изменить, ведь приходится обрабатывать каждую ячейку таблицы и обрабатывать дня неё данные, которые она содержит, и правила их отображения.
Что скажете?
Я поработал над указанными ошибками, но исправил не все.
Во-первых, что исправил:
>Советую убрать опцию переименования таблиц через конфиг, это требует много усилий, а выгода неочевидна.
Убрал из конфига, в PDO обращаюсь к таблицам по имени. Теперь их названия прибиты гвоздями. Не уверен, что это лучше, но сделал.
>Советую убрать реальные даты, названия компаний, номера и фамилии из скриншота, заменить на вымышленные.
Убрал
>Тут код отформатирован ужасно: https://github.com/tsubaku/flights/blob/master/submit.php
Переформатировал. Теперь правильно? Перевёл в camelCase названия пхп-функций. Переменные не переводил, их слишком много.
>Если ты отдаешь JSON, то тип ответа должен быть application/json, не надо изобретать свои стандарты. И логично заголовки ставить не в начале скрипта, а перед отдачей самого JSON
Заменил text/plain на application/json везде, где возвращается JSON. Перенёс хидеры к echo json_encode. Нужны ли хидеры там, где только echo? А там, где вообще ничего нет, просто вызов функции?
> $pass = md5(md5(trim($pass)));
>Безопаснее использовать соленый хеш, как описано в моем уроке https://github.com/codedokode/pasta/blob/master/security/password-hashing.md
Заменил md5 на password_hash/password_verify
>При загрузке картинок нет проверки типа файла, человек загрузит .png или .txt, а ты его переименуешь в .jpg например.
Сделал проверку и корректное расширение для jpg, png, gif, остальным типам скрипт отказывает в загрузке.
> https://github.com/tsubaku/flights/blob/master/show_list_clients.php#L10
> while(list ($key, $val) = each ($_POST)){
>Это давно устарело, нужно использовать foreach тут
Переделал
>Название функции должно начинаться с глагола, то есть не protection, а redirectIfNoPrivileges(...)
Заменил на verifyAuthorization
> <a href='#' class='a_button_delete'
Ссылка должна куда-то вести. Для создания кнопки есть тег button.
Оформил в виде button. Немного поехала вёрстка кнопки, потом поправить.
> while ($i <= count($ru_rows_array)-1){
Тут нужно использовать foreach. Ты сишник наверно? Не надо тянуть плохие практики из Си в язык, где есть foreach.
Заменил в нескольких местах count на foreach
> if (is_null($_COOKIE['id'])
Это неправильно и вызовет ошибку, если в массиве нет ключа 'id'. У тебя наверно включено игнорирование предупреждений, или же ты не смотришь в логи ошибок, раз этого не видишь. Нужно использовать array_key_exists или isset здесь.
Хм, никаких ошибок в логах. Хотя, может быть я просто проверил не все случаи. Заменил is_null на empty.
https://github.com/tsubaku/flights/blob/master/functions.php#L187
> $info = getimagesize($path);
>Тут не проверяется вариант, когда функция вернет вместо массива false.
Добавил проверку
Что исправил с оговорками:
>В шаблонах у тебя вроде бы есть повторяющиеся куски - шапка страницы.
Шапки немного повторяются, но всё же есть различия и не думаю, что сливать общие части имеет смысл. Плюс, так их легче воспринимать. Я разделил скрипт core.js, вынеся в отдельные файлы скрипты менеджера и охранника, а в шаблонах убрал загрузку лишних скриптов.
>https://github.com/tsubaku/flights/blob/master/index.php#L10
> if ($user_level == 9) {
>Тут нужно ииспользовать константу с понятным названием вместо цифры
> $level = 'manager';
>И тот тоже желательно константу.
Немного переписал функцию проверки, теперь она возвращает ид, уровень доступа и фамилию. Проверку оставил по тому же условию.
> echo "<br />";
В HTML слеш в конце тега не ставится, в отличие от XML/XHTML.
Так у меня как раз XHTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
> https://github.com/tsubaku/flights/blob/master/functions.php#L292
> header("Location: status_codes.php?result=403");
Если ты хочешь отдать код ответа HTTP, то надо его отдавать сразу. Потому что редирект - это код вроде 302. То есть ты вместо отдачи кода 403 отдаешь код 302 в ответ на запрос. И вместо "доступ запрещен" говоришь "страница переехала на другой адрес".
Я так и не понял, как сделать так, чтобы браузер при ошибках показывал суть ошибки. Ну или хотя бы стандартные коды. Так что просто заменил все редиректы на header("Location: login.php");
Что не удалось:
>Выделить публичную папку (т.е. папку для файлов, которые можно запросить снаружи) отдельно. Сейчас у тебя по сути все лежит в публичной папке веб-сервера, что небезопасно. Например, можно скачать шаблоны и увидеть их исходный код, а также скачать конфиг.
Выделил папку core, в неё перенёс все НЕ публичные пхп, шаблоны и закачиваемые фотографии. Но как закрыть её, не понимаю. .httaccess полностью рубит доступ и скрипты просто не работают. Как сделать так, чтобы сервер обращаться к ним мог, а левый юзер нет, я не нашёл информации.
>Тут https://github.com/tsubaku/flights/blob/master/show_list_clients.php в одном файле смешана логика и вывод данных в HTML, почитай про шаблоны http://web.archive.org/web/20161119062218/www.phpinfo.su/articles/practice/shablony_v_php.html
Немного переписал и упростил вывод таблиц охранников и клиентов, но как их шаблонизировать, я не знаю (статью читал). Данные в ячейки подставляются в цикле, имена ячеек тоже. При шаблонизации для каждой ячейки придётся писать отдельный вызов, получится монструозно.
>https://github.com/tsubaku/flights/blob/master/functions.php#L5
>Тут слишком сложная функция с слишком большой глубиной отступов
Да, функция монструозная. Я не знаю, как её изменить, ведь приходится обрабатывать каждую ячейку таблицы и обрабатывать дня неё данные, которые она содержит, и правила их отображения.
Что скажете?
http://ideone.com/lI5U84
Кто то может подсказать почему не работает функция увольнения. 168 Строка начала функции, в конце неё делаю ансет трём работникам. А в итоге все равно 101 работник.
>get_Workers_For_Destruction
:)
http://php.net/unset
>// удаляем один элемент массива
>unset($array['element']);
Больше Разрушителей в энтот тред!
Ещё что-то помню про отключение проверки внешних ключей на уровне СУБД. Это вопрос по поводу парсера старых/новых тредов: https://github.com/someApprentice/phpClub/tree/master/tests/ThreadParser
Прошу не проверять xpath-запросы, они скорее всего будут переписаны.
Удобно ли пхп-макаке кодить под линуксом? Есть некий аналог open server? Чтобы можно было легко переключаться между версиями апача, пхп, майэскьюэль без дрочки в консоле?
И раз уж спросил. я не шарю в линуксе и как там все устроено, поэтому вопрос возможно тупой, но Можно переустановить систему например с минт на убунту или наоборот без потери софтины и ее настроек?
перекатывайся в Debian, мне уже четвертый месяц нрааится. если будешь переустанавливать, то софт тоже постигнет сия участь.
просто приготовься к ебле с линухом(рано или поздно заебешься с какой нибудь проблемой)
Без консоли в линуксе никак, но в один момент ты поймешь, что это не минус, а преимущество. Возня есть, но если ты все поставил как надо, то оно будет стоят как надо годами. Алсо, в винде тоже закидонов хватает. Во многих ситуациях, где в линуксе надо прописать одну команду в консоли, которая гарантировано сработает, для винды надо скачивать какой-нибудь экзешник и молиться, чтобы все встало как надо.
Если есть деньги, то можешь купить мак. Это считай линукс, только удобный и красивый. Там тебе и МАМП будет, и нжинкс будет в родной среде вариться, и права доступа к файлам по человечески. В общем, все плюсы линукса в приятной оболочке.
хз что такое опенсервер, но по описанию унреал подходит генту
немного поебаться с установкой, если ты вообще не шаришь (но нужно уметь читать)
всякое лишнее говно супер легко убирается юз флагами
переключение между пхп\руби\питон\ядрами\видеодрайверами\почти-чем-угодно за 2 клика типа:
>eselect php list
>eselect php set 2
сам на линуксе <год, генту единственный юзабельный дистр
>если будешь переустанавливать, то софт тоже постигнет сия участь
да ну нах. Если я захочу перебить систему с линукса на линукс, то софтине пизда?
>Без консоли в линуксе никак
Я умею в консоль и понимаю, что пользоваться консолью это конечно круто, но я в рот ебал эти понты, когда можно два раза мышкой кликнуть
>>1021509
Я не шарю. Для меня дистрибутивы линукса отличаются только внешним видом
>Я умею в консоль и понимаю, что пользоваться консолью это конечно круто, но я в рот ебал эти понты, когда можно два раза мышкой кликнуть
Я так понимаю, про композер ты даже и не слышал?
это я понял, но как он поможет мне также быстро сменить версию пхп или апача, как я делаю это в опен сервере?
= тому сколько ебли поставить memcache в опенсервере , алсо для смены можно сделать скрипт который так же по запуску будет менять как и 2 щелчка в GUI
спасибо, добра
Спасибо.
>>1020900
>ОП проверь плз. Задача про компанию вектор
Теперь еще с одной антикризисной мерой.
http://ideone.com/4zGFfs
Линукс > Виндовс для разработчика
Бери mint с ним будет меньше всего мороки
С gentu тебя тролят, mac оверпрайс
Для смены версий пхп и прочего хорошо бы освоить вагрант или докер, т.к. модно, молодёжно и пригодится
> add_departament
> get_Count_Workers
Что за нестандартный стиль названий функций? PSR рекомендует camelCase для методов:
- https://svyatoslav.biz/misc/psr_translation/#_PSR-1
- https://svyatoslav.biz/misc/psr_translation/#_PSR-2
> public function print_Info()
Вот это лучше бы вынести из Компании наружу, так как у каждого класса должна быть своя зона ответственности. Если у Компании зона отвественности - хранить список департаментов и считать по ним статистику, то вывод информации - это какая-то другая деятельность, которая явно должна делаться в другом месте.
Плюс методы вроде получения затрат на зарплату - они довольно универсальные и могут исопльзоваться кем угодно, но метод вывода на экран - он сильно специфический и написан для одной конкретной задачи, не пригодится для другой и его лучше убрать из класса.
Немного наверно непонятное объяснение получилось, но суть в том, что код будет аккуратнее, если Компания будет хранить информацию о компании, а вывод ее будет делаться в другом месте кода.
> //Cократить в каждом департаменте 40% (округляя в большую сторону) инженеров,
> //преимущественно самого низкого ранга.
> public function Destruction_Workers
Тут та же проблема. Это сильно специфический метод, написанный под одну конкретную задачу (антикризисные меры), и его лучше вынести в отдельный класс. А так, ты по сути взял код, который должен быть в отдельном классе и размазал по Компании и Департаменту.
Иначе представь, завтра тебе понадобится решить еще какую-то задачу, ты допишешь еще код в Компанию, потом еще, и получится класс-монстр который умеет делать все на свете.
Гораздо аккуратнее будет если Компания будет заведовать списком департаментов, а специфичные вещи вроде "найти и уволить 40% рабочих" будут в отдельном классе для антикризисных мер.
Эту идею (каждый класс занимается своим делом) очень важно понять, чтобы писать аккуратный код.
Для антикризисных мер стоит сделать отдельный класс, и метод, который берет Компанию и делает в ней нужные изменения.
> Destruction_Workers
Имена функций начинаются с глаголов, сделатьЧтоТо
> public function add_Workers($count, $rank, $proffesion, $is_Head)
Этот метод сам создает работников, и не позволяет добавить уже созданного где-то в другом месте работника. Лучше сделать добавление именно готового объекта, это будет универсальнее.
> public function get_Workers_And_Destruction($count_in_percent,$proffesion)
Тут функция просто создана методом копирования кода. Так не годится. Нужно убрать повторяющийся код.
Такой код тяжело читать, так как трудно понять, чем именно один блок кода отличается от другого.
Также, у тебя выводятся предупреждения, которые надо исправить:
> PHP Notice: Undefined variable: sum_salary in /home/UH8YEW/prog.php on line 139
> PHP Notice: Undefined variable: sum_pages in /home/UH8YEW/prog.php on line 155
> PHP Notice: Undefined variable: sum_salary in /home/UH8YEW/prog.php on line 139
> PHP Notice: Undefined variable: sum_coffee in /home/UH8YEW/prog.php on line 147
> PHP Notice: Undefined variable: sum_pages in /home/UH8YEW/prog.php on line 155
> add_departament
> get_Count_Workers
Что за нестандартный стиль названий функций? PSR рекомендует camelCase для методов:
- https://svyatoslav.biz/misc/psr_translation/#_PSR-1
- https://svyatoslav.biz/misc/psr_translation/#_PSR-2
> public function print_Info()
Вот это лучше бы вынести из Компании наружу, так как у каждого класса должна быть своя зона ответственности. Если у Компании зона отвественности - хранить список департаментов и считать по ним статистику, то вывод информации - это какая-то другая деятельность, которая явно должна делаться в другом месте.
Плюс методы вроде получения затрат на зарплату - они довольно универсальные и могут исопльзоваться кем угодно, но метод вывода на экран - он сильно специфический и написан для одной конкретной задачи, не пригодится для другой и его лучше убрать из класса.
Немного наверно непонятное объяснение получилось, но суть в том, что код будет аккуратнее, если Компания будет хранить информацию о компании, а вывод ее будет делаться в другом месте кода.
> //Cократить в каждом департаменте 40% (округляя в большую сторону) инженеров,
> //преимущественно самого низкого ранга.
> public function Destruction_Workers
Тут та же проблема. Это сильно специфический метод, написанный под одну конкретную задачу (антикризисные меры), и его лучше вынести в отдельный класс. А так, ты по сути взял код, который должен быть в отдельном классе и размазал по Компании и Департаменту.
Иначе представь, завтра тебе понадобится решить еще какую-то задачу, ты допишешь еще код в Компанию, потом еще, и получится класс-монстр который умеет делать все на свете.
Гораздо аккуратнее будет если Компания будет заведовать списком департаментов, а специфичные вещи вроде "найти и уволить 40% рабочих" будут в отдельном классе для антикризисных мер.
Эту идею (каждый класс занимается своим делом) очень важно понять, чтобы писать аккуратный код.
Для антикризисных мер стоит сделать отдельный класс, и метод, который берет Компанию и делает в ней нужные изменения.
> Destruction_Workers
Имена функций начинаются с глаголов, сделатьЧтоТо
> public function add_Workers($count, $rank, $proffesion, $is_Head)
Этот метод сам создает работников, и не позволяет добавить уже созданного где-то в другом месте работника. Лучше сделать добавление именно готового объекта, это будет универсальнее.
> public function get_Workers_And_Destruction($count_in_percent,$proffesion)
Тут функция просто создана методом копирования кода. Так не годится. Нужно убрать повторяющийся код.
Такой код тяжело читать, так как трудно понять, чем именно один блок кода отличается от другого.
Также, у тебя выводятся предупреждения, которые надо исправить:
> PHP Notice: Undefined variable: sum_salary in /home/UH8YEW/prog.php on line 139
> PHP Notice: Undefined variable: sum_pages in /home/UH8YEW/prog.php on line 155
> PHP Notice: Undefined variable: sum_salary in /home/UH8YEW/prog.php on line 139
> PHP Notice: Undefined variable: sum_coffee in /home/UH8YEW/prog.php on line 147
> PHP Notice: Undefined variable: sum_pages in /home/UH8YEW/prog.php on line 155
Не надо добавлять бесполезные посты в этот тред
>>1021671
да
>>1021505
Это не линукс, например, там нет неймспейсов тех же.
>>1021439
> Есть некий аналог open server? Чтобы можно было легко переключаться между версиями апача, пхп, майэскьюэль без дрочки в консоле?
не знаю, может и нет, я сам привык консолью пользоваться и GUI видеть не могу.
> Можно переустановить систему без потери софтины и ее настроек?
Ты можешь сделать у себя на жестком диске несколько разделов, в один поставить винду, в другой линукс, а на третьем хранить данные, доступные из обоих систем. При этом, если повозиться, то можно сделать переразбиение без уничтожения данных на диске (partition magic это умеет), лишь бы места было достаточно.
Настройки в линуксе обычно хранятся в файлах в /etc, которые легко забекапить и не беспокоиться про переустановку. Также, в линуксе обычно при удалении программы через менеджер пакетов ее настройки не удаляются.
Насчет разных версий PHP - в линуксе есть штука https://github.com/phpbrew/phpbrew которая умеет скачивать и компилировать нужные версии PHP, а потом переключать переменные окружения, чтобы их использовать. Разумеется, тебе придется изучить, как она работает. А так, большинство версий линукса не поддерживают стандартным способом установку 2 версий одной программы.
>>1021482
Только Debian лучше ставить Testing, а то в Stable софт стабильный, но старый.
>>1021432
В смысле, "как"? Не очень понятно, как ответить на твой вопрос. Проектируешь, как это должно работать, и реализуешь.
Не надо добавлять бесполезные посты в этот тред
>>1021671
да
>>1021505
Это не линукс, например, там нет неймспейсов тех же.
>>1021439
> Есть некий аналог open server? Чтобы можно было легко переключаться между версиями апача, пхп, майэскьюэль без дрочки в консоле?
не знаю, может и нет, я сам привык консолью пользоваться и GUI видеть не могу.
> Можно переустановить систему без потери софтины и ее настроек?
Ты можешь сделать у себя на жестком диске несколько разделов, в один поставить винду, в другой линукс, а на третьем хранить данные, доступные из обоих систем. При этом, если повозиться, то можно сделать переразбиение без уничтожения данных на диске (partition magic это умеет), лишь бы места было достаточно.
Настройки в линуксе обычно хранятся в файлах в /etc, которые легко забекапить и не беспокоиться про переустановку. Также, в линуксе обычно при удалении программы через менеджер пакетов ее настройки не удаляются.
Насчет разных версий PHP - в линуксе есть штука https://github.com/phpbrew/phpbrew которая умеет скачивать и компилировать нужные версии PHP, а потом переключать переменные окружения, чтобы их использовать. Разумеется, тебе придется изучить, как она работает. А так, большинство версий линукса не поддерживают стандартным способом установку 2 версий одной программы.
>>1021482
Только Debian лучше ставить Testing, а то в Stable софт стабильный, но старый.
>>1021432
В смысле, "как"? Не очень понятно, как ответить на твой вопрос. Проектируешь, как это должно работать, и реализуешь.
Вообще, в MySQL есть раздел мануала на эту тему https://dev.mysql.com/doc/refman/5.5/en/optimizing-innodb-bulk-data-loading.html
По моему опыту, большие INSERT работают довольно хорошо и отключение ключей нужно заметно разве только при импорте очень больших объемов. Самый значительный эффект дает отказ от вставки каждой записи отдельной транзакцией за счет мультиинсертов либо за счет вставки группы записей одной транзакцией. Так как фиксация транзакции требует определенных затрат времени.
Что касается Доктрины, то должен сразу предупредить, что она с большими объемами данных работает неоптимально и лучше всего это делать без нее (например, загрузка большого числа записей со связями может занимать раз в 10 дольше чем загрузка их в массив через PDO). Тут лучше сделать микробенчмарк и оченить разницу, может она не такая и большая, чтобы отказываться от возможности работать с удобными объектами.
При тестировании надо учесть, что Доктрине может потребоваться создать кеш метаданных, потому лучше сначала вставить 1 запись, а только потом начинать измерения.
Пример, который приведен в мануале, использует flush для группы записей, чтобы вставлять N записей одной транзакцией, и clear, чтобы очистить память (так как Доктрина хранит ссылки на все управляемые ей объекты и потребление памяти без этого будет быстро расти, а также будет змедляться flush, так как он обходит все объекты). Недостаток clear в том,что он убирает все объекты из-под управления доктрины (то есть делает на них detach) и его нельзя применять, если какой-то другой код держит ссылки на эти объекты, и планирует дальше с ними работать. То есть clear годится только для каких-то скриптов импорта, но его не стоит использовать в середине приложения, так как он сломает загруженные ранее сущности.
В генте быстрая смена версий пхп и прочего из коробки в виде системы слотов тащемта, не пизди если не шаришь. Гента ультрагибкая и удобная штука, ее можно подогнать под любые задачи, просто порог вхождения несколько выше чем у дебиана например. Если не гента, то только дебиан, все эти коляски в виде его форков типа минта или там убунты вообще не нужны.
Пришел джуном, поставили в парное программирование с более опытным специалистом, начал делать АПИ для одной системы. Работаю с фреймворком, оперативными хранилищами, серверами очереди, и очевидно с БД. Сейчас все примерно так же, только работаю один.
https://github.com/tsubaku
Сначала отвечу на пост:
> в PDO обращаюсь к таблицам по имени. Теперь их названия прибиты гвоздями. Не уверен, что это лучше, но сделал.
Думаю, лучше, так как код будет проще читать. Я ни разу не сталкивался с тем, чтобы переименование было нужно, но вот разбираться в большом проекте, когда там используются переменные или константы вместо настоящих имен таблиц - неудобно.
Зачем оно вообще нужно? Такое (префиксы имен таблиц) делали много лет назад, чтобы разместить 2 проекта в одной базе, так как нищехостинги требовали отдельные деньги за вторую. Сейчас это по моему неактуально, берешь дешевый VPS и создаешь сколько угодно баз.
> Переформатировал. Теперь правильно?
Не очень:
https://github.com/tsubaku/flights/blob/master/login.php
Тут нужно убрать самый первый отступ (после <?php), то есть строка require_once('./core/php/functions.php'); идет без отступа. Для отступов лучше использовать 4 пробела, а не таб.
https://github.com/tsubaku/flights/blob/master/core/php/submit.php
Тут отступы вообще разные. Почему отступ в строке 22 - 8 пробелов? должно быть 4. И почему там так много пустых строк? Пока что плохо.
Рекомендации PSR можно почитать тут в переводе
- https://svyatoslav.biz/misc/psr_translation/#_PSR-1
- https://svyatoslav.biz/misc/psr_translation/#_PSR-2
Код можно форматировать автоматически, через сайт или IDE, вот ссылка https://gist.github.com/codedokode/8759492
Не понимаю, в чем проблема прогнать файл через сайт или нажать комбинацию клавиш в IDE.
> Нужны ли хидеры там, где только echo? А там, где вообще ничего нет, просто вызов функции?
header логично ставить радом с echo так как они относятся к одной задаче, и header должен срабатывать только когда выводится JSON. А когда ты их ставишь в разных местах, то это во-первых нелогично (мы сначала сообщаем, что будет выведен JSON, а только потом где-то в другом месте его выводим), во-вторых может вести к ошибкам, когда выводится header с application/json а потом выводится не JSON, а обычный текст или например сообщение об ошибке.
То есть нелогично функцию вывода JSON разделять на 2 части и разбрасывать их в разные места кода.
Кстати, тут тоже нелогично: https://github.com/tsubaku/flights/blob/master/core/php/show_list_clients.php
В заголовках указан тип text/plain, а затем идет вывод HTML кода.
И еще, у тебя по прежнему остается проблема копипасты. Например антикеширующие заголовки ты копипастишь из файла в файл, а надо сделать функцию с понятным названием и вызывать ее. Копипаста это плохо, от нее надо избавляться.
> Сделал проверку и корректное расширение для jpg, png, gif, остальным типам скрипт отказывает в загрузке.
Пока не очень удачно. Тут https://github.com/tsubaku/flights/blob/master/core/php/submit.php#L25 ты проверяешь тип файла, который берется из тела POST запроса и указывается браузером. Но браузер может там указать что угодно. Надежднее проверить расширение.
>> if (is_null($_COOKIE['id'])
>> Это неправильно и вызовет ошибку, если в массиве нет ключа 'id'.
> Хм, никаких ошибок в логах.
Вот пример, показывающий ошибку: http://ideone.com/bMeVWL
Возможно у тебя в php.ini включено игнорирование ошибок с помощью настройки error_reporting (зачем так делать??) или отключено их логгирование. Или у тебя всегда есть эта кука.
> Шапки немного повторяются, но всё же есть различия и не думаю, что сливать общие части имеет смысл. Плюс, так их легче воспринимать.
Это копипаста и ее надо убрать. Очевидно же, что у страниц в твоем проекте будут общая шапка, и может быть, подвал. И значит они должны быть вынесены отдельно, а не копипаститься.
> Я так и не понял, как сделать так, чтобы браузер при ошибках показывал суть ошибки. Ну или хотя бы стандартные коды. Так что просто заменил все редиректы на header("Location: login.php");
Ты выводишь HTTP заголовок, затем тело страницы. Что тут сложного?
header("HTTP/1.0 500 Internal Error");
echo "Everything is broken, sorry\n";
die();
Я вообще не понимаю, что сложного так сделать и зачем тут понадобился редирект.
> Выделил папку core, в неё перенёс все НЕ публичные пхп, шаблоны и закачиваемые фотографии. Но как закрыть её, не понимаю.
У сервера есть такая настройка, как "корневая папка" (в Апаче она называется document root, в нгинксе root). Ты создаешь у себя папку public и в настройках веб-севрера прописываешь путь к ней как document root, например в Апаче:
DocumentRoot /var/www/example.com/public/
И в этом случае все остальные файлы оказываются за пределами папки и недоступны снаружи. Без всяких htaccess. ты проблему не с той стороны решаешь.
> Немного переписал и упростил вывод таблиц охранников и клиентов, но как их шаблонизировать, я не знаю
Элементарно это делается. В скрипте-контроллере ты подготавливаешь данные:
$guards = getGuardsList();
// подключаем шаблон
require 'templates/guards.phtml';
В шаблоне формируешь и выводишь HTML страницу:
<?php require __DIR__ . '/header.php'; ?>
<h1>Охранники</h1>
<ul>
<?php foreach ($guards as $guard): ?>
<li><?= htmlspecialchars($guard['name']) ?></li>
<?php endforeach ?>
</ul>
<?php require __DIR__ . '/footer.php'; ?>
> https://github.com/tsubaku/flights/blob/master/core/php/functions.php#L224
> unset($row_content); // разорвать ссылку на последний элемент
Эта строчка вообще смысла не несет, так как она стоит в конце функции, а все локальные переменную удаляются при выходе из функции.
Вот еще проблемное место:
> function showTable($year, $month)
> ...
> $stmt = $pdo->query('INSERT INTO flights () VALUES()'); //Добавляем пустую строку
Функция вывода таблицы не должна ее модифицировать.
> https://github.com/tsubaku/flights/blob/master/core/php/write_in_table.php
Тут нечитаемая стена кода, надо выносить из нее отдельные функции.
> Вопрос про функцию showTable()
> Да, функция монструозная. Я не знаю, как её изменить, ведь приходится обрабатывать каждую ячейку таблицы и обрабатывать дня неё данные, которые она содержит, и правила их отображения.
Сначала нужно разделить получение данных и их вывод. Сначала получаем все данные из БД, только потом выводим.
При этом часть кода можно выносить в отдельные функции. Вот например вначале идет кусок лапши, получающий список рейсов между 2 датами. Его легко вынести в отдельную функцию:
$flights = getFlightsInRange($fromDate, $toDate);
Вот мы заменили 8 строк лапши на один вызов функции. И эту функцию мы сможем вызывать и в других местах, если нам понадобится список рейсов там.
Точно так же можно вынести например получение списка охранников (getGuardList()), получение названия месяца по номеру (getMonthName()), и тд.
После того, как все данные выбраны в переменные, вызываем шаблон для вывода HTML кода.
HTML код выводить, как у тебя, с помощью echo, очень неудобно и неэффективно.
Вообще, тебе нужно учиться разбивать код на отдельные действия (функции), у которых четко определены входные и выходные данные. Без этого за написание таких приложений вообще браться нельзя.
Пока ты просто пишешь длинную последовательность действий, а надо разбивать ее на шаги.
Также, тебе нужно как-то организовать файлы и функции. Сейчас я логики не вижу, файлы называются как попало, функции тоже по ним как-то произвольно раскиданы. Должна быть какая-то логика.
Соответственно, сейчас тебе надо работать над разделением:
- вынести весь HTML код в шаблоны
- вынести весь SQL-код в функции в отдельном файле или файлах, то есть сделать отдельный слой доступа к базе данных, а не размазывать это по всему коду
Я еще раз напомню, что у нас в ОП посте есть задача на список студентов. Хоть она и называется "задача", но там много комментариев и по сути это что-то вроде сборника полезных советов по написанию приложений с формами и таблицами. То есть приложение того же типа, что и у тебя. И тебе желательно найти время ее прочитать, так как у меня нет желания пересказывать тут все ее содержимое по второму разу.
https://github.com/tsubaku
Сначала отвечу на пост:
> в PDO обращаюсь к таблицам по имени. Теперь их названия прибиты гвоздями. Не уверен, что это лучше, но сделал.
Думаю, лучше, так как код будет проще читать. Я ни разу не сталкивался с тем, чтобы переименование было нужно, но вот разбираться в большом проекте, когда там используются переменные или константы вместо настоящих имен таблиц - неудобно.
Зачем оно вообще нужно? Такое (префиксы имен таблиц) делали много лет назад, чтобы разместить 2 проекта в одной базе, так как нищехостинги требовали отдельные деньги за вторую. Сейчас это по моему неактуально, берешь дешевый VPS и создаешь сколько угодно баз.
> Переформатировал. Теперь правильно?
Не очень:
https://github.com/tsubaku/flights/blob/master/login.php
Тут нужно убрать самый первый отступ (после <?php), то есть строка require_once('./core/php/functions.php'); идет без отступа. Для отступов лучше использовать 4 пробела, а не таб.
https://github.com/tsubaku/flights/blob/master/core/php/submit.php
Тут отступы вообще разные. Почему отступ в строке 22 - 8 пробелов? должно быть 4. И почему там так много пустых строк? Пока что плохо.
Рекомендации PSR можно почитать тут в переводе
- https://svyatoslav.biz/misc/psr_translation/#_PSR-1
- https://svyatoslav.biz/misc/psr_translation/#_PSR-2
Код можно форматировать автоматически, через сайт или IDE, вот ссылка https://gist.github.com/codedokode/8759492
Не понимаю, в чем проблема прогнать файл через сайт или нажать комбинацию клавиш в IDE.
> Нужны ли хидеры там, где только echo? А там, где вообще ничего нет, просто вызов функции?
header логично ставить радом с echo так как они относятся к одной задаче, и header должен срабатывать только когда выводится JSON. А когда ты их ставишь в разных местах, то это во-первых нелогично (мы сначала сообщаем, что будет выведен JSON, а только потом где-то в другом месте его выводим), во-вторых может вести к ошибкам, когда выводится header с application/json а потом выводится не JSON, а обычный текст или например сообщение об ошибке.
То есть нелогично функцию вывода JSON разделять на 2 части и разбрасывать их в разные места кода.
Кстати, тут тоже нелогично: https://github.com/tsubaku/flights/blob/master/core/php/show_list_clients.php
В заголовках указан тип text/plain, а затем идет вывод HTML кода.
И еще, у тебя по прежнему остается проблема копипасты. Например антикеширующие заголовки ты копипастишь из файла в файл, а надо сделать функцию с понятным названием и вызывать ее. Копипаста это плохо, от нее надо избавляться.
> Сделал проверку и корректное расширение для jpg, png, gif, остальным типам скрипт отказывает в загрузке.
Пока не очень удачно. Тут https://github.com/tsubaku/flights/blob/master/core/php/submit.php#L25 ты проверяешь тип файла, который берется из тела POST запроса и указывается браузером. Но браузер может там указать что угодно. Надежднее проверить расширение.
>> if (is_null($_COOKIE['id'])
>> Это неправильно и вызовет ошибку, если в массиве нет ключа 'id'.
> Хм, никаких ошибок в логах.
Вот пример, показывающий ошибку: http://ideone.com/bMeVWL
Возможно у тебя в php.ini включено игнорирование ошибок с помощью настройки error_reporting (зачем так делать??) или отключено их логгирование. Или у тебя всегда есть эта кука.
> Шапки немного повторяются, но всё же есть различия и не думаю, что сливать общие части имеет смысл. Плюс, так их легче воспринимать.
Это копипаста и ее надо убрать. Очевидно же, что у страниц в твоем проекте будут общая шапка, и может быть, подвал. И значит они должны быть вынесены отдельно, а не копипаститься.
> Я так и не понял, как сделать так, чтобы браузер при ошибках показывал суть ошибки. Ну или хотя бы стандартные коды. Так что просто заменил все редиректы на header("Location: login.php");
Ты выводишь HTTP заголовок, затем тело страницы. Что тут сложного?
header("HTTP/1.0 500 Internal Error");
echo "Everything is broken, sorry\n";
die();
Я вообще не понимаю, что сложного так сделать и зачем тут понадобился редирект.
> Выделил папку core, в неё перенёс все НЕ публичные пхп, шаблоны и закачиваемые фотографии. Но как закрыть её, не понимаю.
У сервера есть такая настройка, как "корневая папка" (в Апаче она называется document root, в нгинксе root). Ты создаешь у себя папку public и в настройках веб-севрера прописываешь путь к ней как document root, например в Апаче:
DocumentRoot /var/www/example.com/public/
И в этом случае все остальные файлы оказываются за пределами папки и недоступны снаружи. Без всяких htaccess. ты проблему не с той стороны решаешь.
> Немного переписал и упростил вывод таблиц охранников и клиентов, но как их шаблонизировать, я не знаю
Элементарно это делается. В скрипте-контроллере ты подготавливаешь данные:
$guards = getGuardsList();
// подключаем шаблон
require 'templates/guards.phtml';
В шаблоне формируешь и выводишь HTML страницу:
<?php require __DIR__ . '/header.php'; ?>
<h1>Охранники</h1>
<ul>
<?php foreach ($guards as $guard): ?>
<li><?= htmlspecialchars($guard['name']) ?></li>
<?php endforeach ?>
</ul>
<?php require __DIR__ . '/footer.php'; ?>
> https://github.com/tsubaku/flights/blob/master/core/php/functions.php#L224
> unset($row_content); // разорвать ссылку на последний элемент
Эта строчка вообще смысла не несет, так как она стоит в конце функции, а все локальные переменную удаляются при выходе из функции.
Вот еще проблемное место:
> function showTable($year, $month)
> ...
> $stmt = $pdo->query('INSERT INTO flights () VALUES()'); //Добавляем пустую строку
Функция вывода таблицы не должна ее модифицировать.
> https://github.com/tsubaku/flights/blob/master/core/php/write_in_table.php
Тут нечитаемая стена кода, надо выносить из нее отдельные функции.
> Вопрос про функцию showTable()
> Да, функция монструозная. Я не знаю, как её изменить, ведь приходится обрабатывать каждую ячейку таблицы и обрабатывать дня неё данные, которые она содержит, и правила их отображения.
Сначала нужно разделить получение данных и их вывод. Сначала получаем все данные из БД, только потом выводим.
При этом часть кода можно выносить в отдельные функции. Вот например вначале идет кусок лапши, получающий список рейсов между 2 датами. Его легко вынести в отдельную функцию:
$flights = getFlightsInRange($fromDate, $toDate);
Вот мы заменили 8 строк лапши на один вызов функции. И эту функцию мы сможем вызывать и в других местах, если нам понадобится список рейсов там.
Точно так же можно вынести например получение списка охранников (getGuardList()), получение названия месяца по номеру (getMonthName()), и тд.
После того, как все данные выбраны в переменные, вызываем шаблон для вывода HTML кода.
HTML код выводить, как у тебя, с помощью echo, очень неудобно и неэффективно.
Вообще, тебе нужно учиться разбивать код на отдельные действия (функции), у которых четко определены входные и выходные данные. Без этого за написание таких приложений вообще браться нельзя.
Пока ты просто пишешь длинную последовательность действий, а надо разбивать ее на шаги.
Также, тебе нужно как-то организовать файлы и функции. Сейчас я логики не вижу, файлы называются как попало, функции тоже по ним как-то произвольно раскиданы. Должна быть какая-то логика.
Соответственно, сейчас тебе надо работать над разделением:
- вынести весь HTML код в шаблоны
- вынести весь SQL-код в функции в отдельном файле или файлах, то есть сделать отдельный слой доступа к базе данных, а не размазывать это по всему коду
Я еще раз напомню, что у нас в ОП посте есть задача на список студентов. Хоть она и называется "задача", но там много комментариев и по сути это что-то вроде сборника полезных советов по написанию приложений с формами и таблицами. То есть приложение того же типа, что и у тебя. И тебе желательно найти время ее прочитать, так как у меня нет желания пересказывать тут все ее содержимое по второму разу.
>Тут нужно убрать самый первый отступ (после <?php), то есть строка require_once('./core/php/functions.php'); идет без отступа. Для отступов лучше использовать 4 пробела, а не таб.
Блин, про manager.php, index.php, guard.php и login.php я забыл. Сделаю.
>https://github.com/tsubaku/flights/blob/master/core/php/submit.php
>Тут отступы вообще разные. Почему отступ в строке 22 - 8 пробелов? должно быть 4. И почему там так много пустых строк? Пока что плохо.
Хм, submit.php тоже забыл. Странно. Вроде я все файлы по очереди переформатировал.
>Код можно форматировать автоматически, через сайт или IDE, вот ссылка https://gist.github.com/codedokode/8759492
Через него и делал.
>То есть нелогично функцию вывода JSON разделять на 2 части и разбрасывать их в разные места кода.
Не понял. Там же только одна команда вывода json. В каком смысле "разбивать на 2 части"?
>Кстати, тут тоже нелогично:
>https://github.com/tsubaku/flights/blob/master/core/php/show_list_clients.php
>В заголовках указан тип text/plain, а затем идет вывод HTML кода.
А html - это не text/plain?
>И еще, у тебя по прежнему остается проблема копипасты. Например антикеширующие заголовки ты копипастишь из файла в файл, а надо сделать функцию с понятным названием и вызывать ее. Копипаста это плохо, от нее надо избавляться.
Хорошо, функцию сделаю. Но вот именно проблему копипасты не понимаю. Если что-то работает, и работает правильно, то как это переписывать?
>Но браузер может там указать что угодно. Надежднее проверить расширение.
Я гуглил на эту тему и когда кто-то в похожей ситуации делал проверку по расширению, ему так же указывали, что "клиент может послать что угодно, надёжнее проверять по типу". Олсо, не всё ли равно? Законопослушный юзер отправить jpg под видом jpg и всё будет нормально. А незаконопослушный отправит какую-нибудь НЁХ, но сервер переименует её в jpg и при обращении просто не откроет.
>>1021978
>Возможно у тебя в php.ini включено игнорирование ошибок с помощью настройки error_reporting (зачем так делать??) или отключено их логгирование. Или у тебя всегда есть эта кука.
Не включено. Я вручную удалял из браузера куки, ошибок не было, браузер корректно перенаправлял на страницу логина.
>Очевидно же, что у страниц в твоем проекте будут общая шапка, и может быть, подвал.
Но они не одинаковые. В шапке подключаются разные скрипты, выводится разные title, у охранника там дополнительно прописывается срока для мобильных устройств.
>Ты выводишь HTTP заголовок, затем тело страницы. Что тут сложного?
>Я вообще не понимаю, что сложного так сделать и зачем тут понадобился редирект.
А, так это пишется вручную. Теперь понятно. А редирект для удобства юзера.
>и в настройках веб-севрера прописываешь путь к ней как document root, например в Апаче:
У меня нет доступа к настройкам сервера. Вернее, на локалхосте есть, а вот на продакшене всё крутится у хостера (там всего-то статичный сайт нашей конторы, а этот сервис я делаю как бы его подсистемой).
Я посмотрю, как там это устроено.
>Элементарно это делается. В скрипте-контроллере ты подготавливаешь данные:
Я попробую.
> unset($row_content); // разорвать ссылку на последний элемент
>Эта строчка вообще смысла не несет
Блин, точно.
> function showTable($year, $month)
> ...
> $stmt = $pdo->query('INSERT INTO flights () VALUES()'); //Добавляем пустую строку
>Функция вывода таблицы не должна ее модифицировать.
Ну, в общем, да. Я тоже думал вынести скрипт добавления строки в отдельную функцию, а потом вызывать её, но вызывать-то всё равно придётся. Если в указанном месяце нет ни одного рейса, то должна втоматически создаваться пустая строка для нового рейса и после этого показываться таблица, состоящая из пустой строки.
> https://github.com/tsubaku/flights/blob/master/core/php/write_in_table.php
>Тут нечитаемая стена кода, надо выносить из нее отдельные функции.
Большая часть стены - case. В зависимости от того, куда вставлены данные, скрипт должен либо просто их прописать в базу, либо пересчитать связанные с этой ячейкой другие ячейки строки. Разделить на функции, конечно, можно, и я сделаю, раз так надо.
Остальные комментарии тоже приму к сведению.
>Я еще раз напомню, что у нас в ОП посте есть задача на список студентов.
Я с ней ознакомился. Кое-что применил, что смог. Мне кажется, у меня мозги слишком крепко пропитаны админством и сложно уловить подход программистов. Но я буду продолжать переписывать код и дальше.
>Тут нужно убрать самый первый отступ (после <?php), то есть строка require_once('./core/php/functions.php'); идет без отступа. Для отступов лучше использовать 4 пробела, а не таб.
Блин, про manager.php, index.php, guard.php и login.php я забыл. Сделаю.
>https://github.com/tsubaku/flights/blob/master/core/php/submit.php
>Тут отступы вообще разные. Почему отступ в строке 22 - 8 пробелов? должно быть 4. И почему там так много пустых строк? Пока что плохо.
Хм, submit.php тоже забыл. Странно. Вроде я все файлы по очереди переформатировал.
>Код можно форматировать автоматически, через сайт или IDE, вот ссылка https://gist.github.com/codedokode/8759492
Через него и делал.
>То есть нелогично функцию вывода JSON разделять на 2 части и разбрасывать их в разные места кода.
Не понял. Там же только одна команда вывода json. В каком смысле "разбивать на 2 части"?
>Кстати, тут тоже нелогично:
>https://github.com/tsubaku/flights/blob/master/core/php/show_list_clients.php
>В заголовках указан тип text/plain, а затем идет вывод HTML кода.
А html - это не text/plain?
>И еще, у тебя по прежнему остается проблема копипасты. Например антикеширующие заголовки ты копипастишь из файла в файл, а надо сделать функцию с понятным названием и вызывать ее. Копипаста это плохо, от нее надо избавляться.
Хорошо, функцию сделаю. Но вот именно проблему копипасты не понимаю. Если что-то работает, и работает правильно, то как это переписывать?
>Но браузер может там указать что угодно. Надежднее проверить расширение.
Я гуглил на эту тему и когда кто-то в похожей ситуации делал проверку по расширению, ему так же указывали, что "клиент может послать что угодно, надёжнее проверять по типу". Олсо, не всё ли равно? Законопослушный юзер отправить jpg под видом jpg и всё будет нормально. А незаконопослушный отправит какую-нибудь НЁХ, но сервер переименует её в jpg и при обращении просто не откроет.
>>1021978
>Возможно у тебя в php.ini включено игнорирование ошибок с помощью настройки error_reporting (зачем так делать??) или отключено их логгирование. Или у тебя всегда есть эта кука.
Не включено. Я вручную удалял из браузера куки, ошибок не было, браузер корректно перенаправлял на страницу логина.
>Очевидно же, что у страниц в твоем проекте будут общая шапка, и может быть, подвал.
Но они не одинаковые. В шапке подключаются разные скрипты, выводится разные title, у охранника там дополнительно прописывается срока для мобильных устройств.
>Ты выводишь HTTP заголовок, затем тело страницы. Что тут сложного?
>Я вообще не понимаю, что сложного так сделать и зачем тут понадобился редирект.
А, так это пишется вручную. Теперь понятно. А редирект для удобства юзера.
>и в настройках веб-севрера прописываешь путь к ней как document root, например в Апаче:
У меня нет доступа к настройкам сервера. Вернее, на локалхосте есть, а вот на продакшене всё крутится у хостера (там всего-то статичный сайт нашей конторы, а этот сервис я делаю как бы его подсистемой).
Я посмотрю, как там это устроено.
>Элементарно это делается. В скрипте-контроллере ты подготавливаешь данные:
Я попробую.
> unset($row_content); // разорвать ссылку на последний элемент
>Эта строчка вообще смысла не несет
Блин, точно.
> function showTable($year, $month)
> ...
> $stmt = $pdo->query('INSERT INTO flights () VALUES()'); //Добавляем пустую строку
>Функция вывода таблицы не должна ее модифицировать.
Ну, в общем, да. Я тоже думал вынести скрипт добавления строки в отдельную функцию, а потом вызывать её, но вызывать-то всё равно придётся. Если в указанном месяце нет ни одного рейса, то должна втоматически создаваться пустая строка для нового рейса и после этого показываться таблица, состоящая из пустой строки.
> https://github.com/tsubaku/flights/blob/master/core/php/write_in_table.php
>Тут нечитаемая стена кода, надо выносить из нее отдельные функции.
Большая часть стены - case. В зависимости от того, куда вставлены данные, скрипт должен либо просто их прописать в базу, либо пересчитать связанные с этой ячейкой другие ячейки строки. Разделить на функции, конечно, можно, и я сделаю, раз так надо.
Остальные комментарии тоже приму к сведению.
>Я еще раз напомню, что у нас в ОП посте есть задача на список студентов.
Я с ней ознакомился. Кое-что применил, что смог. Мне кажется, у меня мозги слишком крепко пропитаны админством и сложно уловить подход программистов. Но я буду продолжать переписывать код и дальше.
Работа с исключениями сделана абсолютно неправильно:
> try { }
> catch (\Exception $e) {
> Yii::warning($e->getMessage());
> return $this->redirect(Yii::$app->request->referrer);
Что за бред? В приложении происходит ошибка, и ты просто редиректишь на referer (а кстати, что если он пустой?). При ошибке надо вывести страницу ошибки, а не скрывать этот факт. Это ведь тебе самому потом усложнит поиск причин.
Вообще, у меня иногда ощущение, что кроме меня никто не понимает, как надо работать с ошибками. Везде с ними работают неправильно, ну кто этих людей вообще в программисты пустил.
Вообще, сам код не очень хороший, типичный толстый контроллер, хотя бизнес-логику лучше выносить в отдельные классы-сервисы.
Вот простой пример, чем плох твой код. У тебя есть действие контроллера для рассылки сообщений actionMassSend(). Но что, если нам понадобится вызвать это действие где-то программно? У тебя нет функции вроде sendMassMessage($message, $users) и нам придется писать код заново. Ты не почему-то не додумался вынести это действие в отдельную функцию, а вписал в контроллер, перемешав с кодом получения данные из формы и кодом отдачи ответа пользователю.
>>1021061
Спасибо, сайтгайд хороший.
>>1021030
> Изменение номера - https://ideone.com/KJxmSg
Ок, верно
> Автозамена - https://ideone.com/LaOqC8
Ок, тоже верно
> Вывод email - https://ideone.com/NCD54g
Не найдется email i[|JvanANUS0sqi2PUNCTUMcX,#om
> Grammar Nazi - https://ideone.com/BR95EM
Эти однотипные строки надо объединить в одну регулярку:
$text = preg_replace('/[,](\\S)/ui', ', $1', $text);
$text = preg_replace('/[;](\\S)/ui', '; $1', $text);
$text = preg_replace('/[!](\\S)/ui', '! $1', $text);
И эти объединить:
> $text = preg_replace('/жы/ui','жи', $text);
> $text = preg_replace('/шы/ui','ши', $text);
> $text = preg_replace('/(\\S) а /', '$1, а ', $text);
Нужно еще правило для "но"
Работа с исключениями сделана абсолютно неправильно:
> try { }
> catch (\Exception $e) {
> Yii::warning($e->getMessage());
> return $this->redirect(Yii::$app->request->referrer);
Что за бред? В приложении происходит ошибка, и ты просто редиректишь на referer (а кстати, что если он пустой?). При ошибке надо вывести страницу ошибки, а не скрывать этот факт. Это ведь тебе самому потом усложнит поиск причин.
Вообще, у меня иногда ощущение, что кроме меня никто не понимает, как надо работать с ошибками. Везде с ними работают неправильно, ну кто этих людей вообще в программисты пустил.
Вообще, сам код не очень хороший, типичный толстый контроллер, хотя бизнес-логику лучше выносить в отдельные классы-сервисы.
Вот простой пример, чем плох твой код. У тебя есть действие контроллера для рассылки сообщений actionMassSend(). Но что, если нам понадобится вызвать это действие где-то программно? У тебя нет функции вроде sendMassMessage($message, $users) и нам придется писать код заново. Ты не почему-то не додумался вынести это действие в отдельную функцию, а вписал в контроллер, перемешав с кодом получения данные из формы и кодом отдачи ответа пользователю.
>>1021061
Спасибо, сайтгайд хороший.
>>1021030
> Изменение номера - https://ideone.com/KJxmSg
Ок, верно
> Автозамена - https://ideone.com/LaOqC8
Ок, тоже верно
> Вывод email - https://ideone.com/NCD54g
Не найдется email i[|JvanANUS0sqi2PUNCTUMcX,#om
> Grammar Nazi - https://ideone.com/BR95EM
Эти однотипные строки надо объединить в одну регулярку:
$text = preg_replace('/[,](\\S)/ui', ', $1', $text);
$text = preg_replace('/[;](\\S)/ui', '; $1', $text);
$text = preg_replace('/[!](\\S)/ui', '! $1', $text);
И эти объединить:
> $text = preg_replace('/жы/ui','жи', $text);
> $text = preg_replace('/шы/ui','ши', $text);
> $text = preg_replace('/(\\S) а /', '$1, а ', $text);
Нужно еще правило для "но"
> Можешь объяснить, чем плохи чистые функции, зачем городить эти Utility service?
Я думаю, ради DI, если тебе нужна ссылка на другой сервис, то надо использовать DI. Если не нужна, можно наверно и обычные функции.
>>1020161
Копировать руками ничего не надо, надо автоматизировать деплой, используя скрипты с rsync, ansible или как вариант, деплой через гит.
>>1020741
Какая версия дистрибутива? И почему версия PHP какая-то левая, что еще за blackfire? ты каких-то странных патчей туда наустанавливал, возможно в этом проблема?
Что значит "все ломается"
Из твоего поста ничего понять нельзя.
>>1020506
Ну, тут вроде не уроки, а только среда для создания проверяльшиков задач. Причем она требует устанавливать что-то в консоли (а в винде еще и помучаться), но никаких инструкций и уроков по работе с консолью там нет. Начинающий отвалится уже на этом моменте.
Ну и она не на русском.
А ты видел это? https://github.com/codedokode/task-checker
Я пытаюсь сделать проверяльщик, который будет все писать подробно и на русском.
Ну и если честно, мне вообще не очень нравится идея с рисунками в консоли. Они сначала себя ограничивают, используя консоль, а потом пытаются там делать менюшки и картинки. Не проще ли сразу HTML взять?
>>1020356
Нужно вынести файлы за пределы публичной папки (корня сервера).
> Можешь объяснить, чем плохи чистые функции, зачем городить эти Utility service?
Я думаю, ради DI, если тебе нужна ссылка на другой сервис, то надо использовать DI. Если не нужна, можно наверно и обычные функции.
>>1020161
Копировать руками ничего не надо, надо автоматизировать деплой, используя скрипты с rsync, ansible или как вариант, деплой через гит.
>>1020741
Какая версия дистрибутива? И почему версия PHP какая-то левая, что еще за blackfire? ты каких-то странных патчей туда наустанавливал, возможно в этом проблема?
Что значит "все ломается"
Из твоего поста ничего понять нельзя.
>>1020506
Ну, тут вроде не уроки, а только среда для создания проверяльшиков задач. Причем она требует устанавливать что-то в консоли (а в винде еще и помучаться), но никаких инструкций и уроков по работе с консолью там нет. Начинающий отвалится уже на этом моменте.
Ну и она не на русском.
А ты видел это? https://github.com/codedokode/task-checker
Я пытаюсь сделать проверяльщик, который будет все писать подробно и на русском.
Ну и если честно, мне вообще не очень нравится идея с рисунками в консоли. Они сначала себя ограничивают, используя консоль, а потом пытаются там делать менюшки и картинки. Не проще ли сразу HTML взять?
>>1020356
Нужно вынести файлы за пределы публичной папки (корня сервера).
> Не понял. Там же только одна команда вывода json. В каком смысле "разбивать на 2 части"?
Вывод JSON ответа состоит из 2 действий:
- добавить заголовок Content-Type с значением application/json
- вывести тело ответа (JSON код)
Вопрос был, какой смысл эти неразрывно связанные действия разносить отдельно.
> А html - это не text/plain?
Это text/html: https://ru.wikipedia.org/wiki/Список_MIME-типов
text/plain значит "обычный текст без тегов и форматрования". Браузер отобразит его просто черным текстом на белов фоне как есть.
> Но вот именно проблему копипасты не понимаю. Если что-то работает, и работает правильно, то как это переписывать?
Ты забываешь правило "код пишется для людей".
Проблема копипасты в том, что одинаковый код дублируется многократно. Это раздувает объем исходного кода. Также, при любых исправлениях эти исправления тоже придется делать многократно, что увеличивает затраты времени на них.
Также, в плане чтения кода строка
setNoCacheHeaders();
гораздо понятнее и читабельнее чем 2 строки с header.
> Я гуглил на эту тему и когда кто-то в похожей ситуации делал проверку по расширению, ему так же указывали, что "клиент может послать что угодно, надёжнее проверять по типу
Имя файла присылается всегда, а где гарантия, что браузер правильно определит и пришлет тип? У тебя есть информация, какие типы файлов какой браузер "знает", а какие нет? У меня нет такой информации например. Никто не запрещает прислать браузеру тип application/octet-stream например.
> Не включено. Я вручную удалял из браузера куки, ошибок не было, браузер корректно перенаправлял на страницу логина.
Он вывел ошибку, но ты ее мог не увидеть, если при этом произошел редирект. Я дал пример на ideone, там ошибка есть. Если она не отображается у тебя, то это что-то не так настроено. Попробуй запустить у себя мой код с ideone и проверить.
> В шапке подключаются разные скрипты, выводится разные title, у охранника там дополнительно прописывается срока для мобильных устройств.
А что-то будет одинаковое, например если ты добавишь иконку, то тег везде будет одинаковый. Сама шапка одна и та же, просто ее вид немного меняется. Или ты например завтра меню захочешь добавить.
> У меня нет доступа к настройкам сервера. Вернее, на локалхосте есть, а вот на продакшене всё крутится у хостера (там всего-то статичный сайт нашей конторы, а этот сервис я делаю как бы его подсистемой).
Ну это плохо, получается ты отказываешься от безопасного подхода в пользу небезопасного. Пусть все читают настройки твоей БД, скачивают бекапы и случайно оставленные файлы.
Как костыль ты можешь попробовать загружать свой код на 1 папку выше корня сайта на сервере.
> Я тоже думал вынести скрипт добавления строки в отдельную функцию, а потом вызывать её, но вызывать-то всё равно придётся. Если в указанном месяце нет ни одного рейса, то должна втоматически создаваться пустая строка для нового рейса и после этого показываться таблица, состоящая из пустой строки.
Название функции должно ей соответствовать, если написано "вывести таблицу", то она должна заниматься именно выводом таблицы.
> Кое-что применил, что смог. Мне кажется, у меня мозги слишком крепко пропитаны админством и сложно уловить подход программистов.
Просто там очень много информации в сжатой форме и за раз это не осилить. Прочти один пункт, разберись с ним, а потом как-нибудь переходи к другим.
>>1021998
видимо redis/rabbitmq
> Не понял. Там же только одна команда вывода json. В каком смысле "разбивать на 2 части"?
Вывод JSON ответа состоит из 2 действий:
- добавить заголовок Content-Type с значением application/json
- вывести тело ответа (JSON код)
Вопрос был, какой смысл эти неразрывно связанные действия разносить отдельно.
> А html - это не text/plain?
Это text/html: https://ru.wikipedia.org/wiki/Список_MIME-типов
text/plain значит "обычный текст без тегов и форматрования". Браузер отобразит его просто черным текстом на белов фоне как есть.
> Но вот именно проблему копипасты не понимаю. Если что-то работает, и работает правильно, то как это переписывать?
Ты забываешь правило "код пишется для людей".
Проблема копипасты в том, что одинаковый код дублируется многократно. Это раздувает объем исходного кода. Также, при любых исправлениях эти исправления тоже придется делать многократно, что увеличивает затраты времени на них.
Также, в плане чтения кода строка
setNoCacheHeaders();
гораздо понятнее и читабельнее чем 2 строки с header.
> Я гуглил на эту тему и когда кто-то в похожей ситуации делал проверку по расширению, ему так же указывали, что "клиент может послать что угодно, надёжнее проверять по типу
Имя файла присылается всегда, а где гарантия, что браузер правильно определит и пришлет тип? У тебя есть информация, какие типы файлов какой браузер "знает", а какие нет? У меня нет такой информации например. Никто не запрещает прислать браузеру тип application/octet-stream например.
> Не включено. Я вручную удалял из браузера куки, ошибок не было, браузер корректно перенаправлял на страницу логина.
Он вывел ошибку, но ты ее мог не увидеть, если при этом произошел редирект. Я дал пример на ideone, там ошибка есть. Если она не отображается у тебя, то это что-то не так настроено. Попробуй запустить у себя мой код с ideone и проверить.
> В шапке подключаются разные скрипты, выводится разные title, у охранника там дополнительно прописывается срока для мобильных устройств.
А что-то будет одинаковое, например если ты добавишь иконку, то тег везде будет одинаковый. Сама шапка одна и та же, просто ее вид немного меняется. Или ты например завтра меню захочешь добавить.
> У меня нет доступа к настройкам сервера. Вернее, на локалхосте есть, а вот на продакшене всё крутится у хостера (там всего-то статичный сайт нашей конторы, а этот сервис я делаю как бы его подсистемой).
Ну это плохо, получается ты отказываешься от безопасного подхода в пользу небезопасного. Пусть все читают настройки твоей БД, скачивают бекапы и случайно оставленные файлы.
Как костыль ты можешь попробовать загружать свой код на 1 папку выше корня сайта на сервере.
> Я тоже думал вынести скрипт добавления строки в отдельную функцию, а потом вызывать её, но вызывать-то всё равно придётся. Если в указанном месяце нет ни одного рейса, то должна втоматически создаваться пустая строка для нового рейса и после этого показываться таблица, состоящая из пустой строки.
Название функции должно ей соответствовать, если написано "вывести таблицу", то она должна заниматься именно выводом таблицы.
> Кое-что применил, что смог. Мне кажется, у меня мозги слишком крепко пропитаны админством и сложно уловить подход программистов.
Просто там очень много информации в сжатой форме и за раз это не осилить. Прочти один пункт, разберись с ним, а потом как-нибудь переходи к другим.
>>1021998
видимо redis/rabbitmq
>Что за нестандартный стиль названий функций? PSR рекомендует camelCase для методов:
Думал что стиль названия для всего один. А оказывается для всего разные. fixed
>Вот это лучше бы вынести из Компании наружу, так как у каждого класса должна быть своя зона ответственности. Если у Компании зона отвественности - хранить список департаментов и считать по ним статистику, то вывод информации - это какая-то другая деятельность, которая явно должна делаться в другом месте.
А нормально что он будет в функции которая не в классе, а сама по себе?
>Гораздо аккуратнее будет если Компания будет заведовать списком департаментов, а специфичные вещи вроде "найти и уволить 40% рабочих" будут в отдельном классе для антикризисных мер.
Но разве не компания отвечает за увольнение работников, да и вообще всего что там (в компании) происходит.
>Имена функций начинаются с глаголов, сделатьЧтоТо
Заменил на destroy. А как я понимаю этот глагол пишется с маленькой буквы.
>> public function get_Workers_And_Destruction($count_in_percent,$proffesion)
>Тут функция просто создана методом копирования кода. Так не годится. Нужно убрать повторяющийся код.
Как я понял это про копирование foreach 3 раза. Сделал адекватно.
>Этот метод сам создает работников, и не позволяет добавить уже созданного где-то в другом месте работника. Лучше сделать добавление именно готового объекта, это будет универсальнее.
Добавил метод для поштучного добавления и для массива с кучей рабочих.
>Гораздо аккуратнее будет если Компания будет заведовать списком департаментов, а специфичные вещи вроде "найти и уволить 40% рабочих" будут в отдельном классе для антикризисных мер.
Я сделал отдельный класс. В нем функцию. и дальше если я пытаюсь эту фунецию на компанию использовать то ошибка. Не понимаю как сделать.
Есть еще вопрос насчет того что все переменные в классах закрыты и из за этого приходится делать кучу функций геттеров и сеттеров. Это нормально так делать? Всегда так надо делать? Почему бы не сделать все паблик и тогда код сократится в 2-3 раза, потому что не будет этих бесполезных функций getRank и тд.
Еще вопрос что плохого в классе монстре. Хочешь использовать функцию или сделать. Через поиск проверяешь нет ли такой и используешь/делаешь.
>Что за нестандартный стиль названий функций? PSR рекомендует camelCase для методов:
Думал что стиль названия для всего один. А оказывается для всего разные. fixed
>Вот это лучше бы вынести из Компании наружу, так как у каждого класса должна быть своя зона ответственности. Если у Компании зона отвественности - хранить список департаментов и считать по ним статистику, то вывод информации - это какая-то другая деятельность, которая явно должна делаться в другом месте.
А нормально что он будет в функции которая не в классе, а сама по себе?
>Гораздо аккуратнее будет если Компания будет заведовать списком департаментов, а специфичные вещи вроде "найти и уволить 40% рабочих" будут в отдельном классе для антикризисных мер.
Но разве не компания отвечает за увольнение работников, да и вообще всего что там (в компании) происходит.
>Имена функций начинаются с глаголов, сделатьЧтоТо
Заменил на destroy. А как я понимаю этот глагол пишется с маленькой буквы.
>> public function get_Workers_And_Destruction($count_in_percent,$proffesion)
>Тут функция просто создана методом копирования кода. Так не годится. Нужно убрать повторяющийся код.
Как я понял это про копирование foreach 3 раза. Сделал адекватно.
>Этот метод сам создает работников, и не позволяет добавить уже созданного где-то в другом месте работника. Лучше сделать добавление именно готового объекта, это будет универсальнее.
Добавил метод для поштучного добавления и для массива с кучей рабочих.
>Гораздо аккуратнее будет если Компания будет заведовать списком департаментов, а специфичные вещи вроде "найти и уволить 40% рабочих" будут в отдельном классе для антикризисных мер.
Я сделал отдельный класс. В нем функцию. и дальше если я пытаюсь эту фунецию на компанию использовать то ошибка. Не понимаю как сделать.
Есть еще вопрос насчет того что все переменные в классах закрыты и из за этого приходится делать кучу функций геттеров и сеттеров. Это нормально так делать? Всегда так надо делать? Почему бы не сделать все паблик и тогда код сократится в 2-3 раза, потому что не будет этих бесполезных функций getRank и тд.
Еще вопрос что плохого в классе монстре. Хочешь использовать функцию или сделать. Через поиск проверяешь нет ли такой и используешь/делаешь.
Всем привет. Застрял в самом начале :с
Вот код:
1) <?php
2)
3) error_reporting(-1)
4)
5) echo "Бросаем кубик... \n";
6) $random = mt_rand(1,6) ;
echo "Выпало $random\n";
Выдает ошибку:
PHP Parse error: syntax error, unexpected 'echo' (T_ECHO) in /home/jZlt7x/prog.php on line 4
Я так понимаю у меня что-то не так с кавычками, а что сними не так? Или что не так?
http://codepad.org/nm9jPcpd
перебрал дохуа вариантов, боюсь окончательно ебанутся
>При ошибке надо вывести страницу ошибки
Ну она ругается в лог, а пользователю об это знать и не обязательно, хотя я наверное хотел проставлять там flash message ибо просто редирект это хрень конечно
Это единственная ошибка с исключениями?
> типичный толстый контроллер
Об этом я тоже думал, но я хз, как оценивают код и что там хотят увидеть те люди которые его просят ("Контроллер строк на 300, максимально написанных вами")
Вот я и запихнул туда этот метод, а то в контролере только вызовы сервисов и методов моделей и будут.
Или они хотят видеть патернизацию всего, а логика не так важна...
Увы у меня особо нет времени запилить годный большой резюме-проект, а на текущей работе говнокод и суровая реальность
>Какая версия дистрибутива? И почему версия PHP какая-то левая, что еще за blackfire? ты каких-то странных патчей туда наустанавливал, возможно в этом проблема?
Что значит "все ломается"
Из твоего поста ничего понять нельзя.
это версия пхп, который в коробке хомстед в вагранте скрин с терминала под ссх, там все настроено и установлено заранее, в этом и понт этого вагранта. а вот мкрипта нет. устанавливаю туда, по ссх мкрипт и вылазит при просмотре в браузере: No input file specified везде
смотреть на нее
Спасибо за ответ :)
я тоже тупил на этом месте чето
это математика, а не синтаксис, лол
выплатил 60000 = $paymentTotal
тебе нужно отдать 1270 = $creditBalance
ты отдаешь 5к $paymentTotal = 65k
долг $creditBalance = -3630
if ($creditBalance < 0)
тебе дают сдачу
$paymentTotal= $paymentTotal + $creditBalance;
ну что ты за человек, сделал так же говорю, но правильный результат не выводился
тупо в текстовом варианте
какие вообще есть способы для этого?
С фейсбука ты можешь воспользоваться их API, благо у них неплохая документация с Explorer'ом.
А с любого другого сайта могу посоветовать лишь парсить верстку, советую с мобильной версии.
Я пользовался несколькими библиотечками, быстрее всего оказалась pharse от ressio.
А когда мне было десять лет ПХП еще не изобрели и программировать я мол разве что на БЭСМ
<?
$what="буквы";
$where="здесь буквы кириллицы";
echo mb_strpos($where, $what, 0, 'UTF-8');
?>
Этот код не хочет работать. PHP 7.
><?
>$what="буквы";
>$where="здесь буквы кириллицы";
>echo mb_strpos($where, $what, 0, 'UTF-8');
>?>
Попробуй
<?php
$what="буквы";
$where="здесь буквы кириллицы";
echo mb_strpos($where, $what, 0, 'UTF-8');
Если на ideone, то там не поддерживаются mb-функции, ищи другой сервис выполнения PHP кода.
В чем проявляется "не работает"? Ошибка какая-то пишется или что? Что в логах? Установлено ли расширение mbstring (можно посмотреть в phpinfo())?
FastCGI sent in stderr: "PHP message: PHP Fatal error: Uncaught Error: Call to undefined function mb_strpos() in /var/www/html/test.php:38
И где там посмотреть установлено ли оно? Ввел в поиск ctrf-f - не нашло mbstring.
У меня чистый php-fm на убунте. Как установить mbstring?
Только на macOS. Для установки необходимо смузи
https://www.w3schools.com/php/default.asp
Посмотреть с помощью php -m или функции phpinfo()
Установить так:
apt-cache search php
найти там mbstring и установить с помощью sudo apt-get install
От твоего учебника у тебя только мусор в голове останется.
w3schools не объясняет такие базовые вещи как
foreach ($arr as &$value) {
$value = $value * 2;
}
обрати внимание на амперсанд перед $value
Не говоря про темы, которые ты пропустишь, например:
http://php.net/manual/ru/language.oop5.autoload.php
http://php.net/manual/ru/language.namespaces.php
http://php.net/manual/ru/language.oop5.late-static-bindings.php
Базы для чего? Для натягивания шаблонов на вордпресс - возможно. Для уверенного пользования современными PSR фреймворками - нет не достаточно. Да и вообще, как я указал в начале, w3schools не дает правильного понимания php. Официальная документация методически правильно излагает материал от простого к сложному.
там много заумных объяснений,либо все кратко отчего местами нихуя не понятно,если ты изучал до этого к-л язык то все пойдет конечно норм
<input type="checkbox" name="the_checkbox" value="1" />
Можно ли писать такой код чтобы потом удобнее обрабатывать было в php форму? А то isset'ом проверять не очень как-то.
>Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
Это ебаша по пять часов в день? Сколько мне понадобится времени, если уделять по два часа в день, чтобы достигнуть такого уровня, чтобы взяли на работу хотя бы "за еду"?
На словах ты Лев Толстой - https://ideone.com/S7Xrez
Поиск email - https://ideone.com/d2N8d6
Grammar Nazi - https://ideone.com/925aB2
Опечаточник - https://ideone.com/mpNbLd
>Опечаточник - https://ideone.com/mpNbLd
если в слове больше 1 енг буквы. то не показывает остальные
Сначала проверяет на наличие купюр, если ключ(кол-во купюр) таковой равен нулю, то удаляет её из массива. После сумма делится на последний элемент массива, попутно считая купюры и отнимая один от ключа до тех пор, пока он не станет равен нулю. После следующий и так далее.
БАМП
Так в задании написано "выделяет квадратными скобками первую замененную букву". Разве нужно остальные выделят?
Я после твоих последних постов так и не смог найти силы переписывать программу. Руки опустились.
Когда ты вбрасывал программу в тред, ты думал, что за тебя найдут ошибки.
Теперь ты думаешь, что кто-то даст тебе мотивацию.
Потом у тебя что-то не получиться, и ты попросишь решить проблему за тебя.
Реши блядь уже свои собственные проблемы самостоятельно. Тебе уже охуительно сильно помогают искать ошибки. Цени чужое потраченное на тебя время.
Так делай, если не хочешь чтобы оно было потрачено зря.
>>1025247
Для начала сделайте задачу на студентов из ОП поста. Это конечно не шибко впечатляющий проект, но он вам даст много полезных знаний, а пока вы будете его делать, у вас появится идея что сделать еще.
>>1024908
Ну, если у сайта один пользователь то особой разницы между fpm и built-in сервером и нет.
Так, на твой вопрос сразу ответить не получится. Так как может быть очень много причин. Хорошо бы (если есть время) попробовать найти, в чем именно дело. Для этого надо посмотреть, что происходит в процессе выполнения кода. Тут есть 2 способа:
- расширение xdebug и профайлинг с его помощью. Оно сгенерирует лог (cachegrind), который можно просмотреть специальной программой и увидеть, какие функции занимали сколько времени. Также, можно сгенерировать трейс, показывающий порядок вызова каждой функции, время выполнения и потребление памяти
Стоит помнить только, что включение отладки повлияет на код и он будет работать еще медленнее.
- наблюдение за программой через strace. Эта линукс-утилита показывает системные вызовы (запросы программы к операционной системе), которые делает твое приложение. Минус в том, что будут показаны только обращения к файлам, выделение памяти, то есть то, за чем нужно обращаться к ОС, а внутренняя работы программы будет не видна. С другой стороны, симфони делает десятки тысяч разных операций и лог strace, который меньше по объему, удобнее просматривать.
- наконец, есть еще poor man profiling, то есть ручная расстановка по коду команд вывода текущей функции и время, прошедшее от начала запроса. Это конечно может занять много времени.
Если у тебя есть время, я тебе рекомендую попробовать эти варианты. Это даст тебе полезный опыт, который может пригодиться в будущем. Я готов помочь советами если что-то не заработает. Это позволит увидеть, какие именно операции делает код и где тратится время.
Я тебе советую сделать какой-то тестовый контроллер, который просто выводит hello world, чтобы исключить проблемы в твоем коде.
Также, есть несколько вещей, которые можно попробовать сделать без профайлинга:
- включить opcache. Это расширение кеширует скомпилированные скрипты в памяти и избавляет от необходимости компилировать их повторно
- проверить настройки Доктрины, особенно если ты используешь много сущностей. Она в зависимости от настроек может собирать метаданные из кода сущностей и генерироват прокси классы на лету, что увеличивает время выполнения
>>1025247
Для начала сделайте задачу на студентов из ОП поста. Это конечно не шибко впечатляющий проект, но он вам даст много полезных знаний, а пока вы будете его делать, у вас появится идея что сделать еще.
>>1024908
Ну, если у сайта один пользователь то особой разницы между fpm и built-in сервером и нет.
Так, на твой вопрос сразу ответить не получится. Так как может быть очень много причин. Хорошо бы (если есть время) попробовать найти, в чем именно дело. Для этого надо посмотреть, что происходит в процессе выполнения кода. Тут есть 2 способа:
- расширение xdebug и профайлинг с его помощью. Оно сгенерирует лог (cachegrind), который можно просмотреть специальной программой и увидеть, какие функции занимали сколько времени. Также, можно сгенерировать трейс, показывающий порядок вызова каждой функции, время выполнения и потребление памяти
Стоит помнить только, что включение отладки повлияет на код и он будет работать еще медленнее.
- наблюдение за программой через strace. Эта линукс-утилита показывает системные вызовы (запросы программы к операционной системе), которые делает твое приложение. Минус в том, что будут показаны только обращения к файлам, выделение памяти, то есть то, за чем нужно обращаться к ОС, а внутренняя работы программы будет не видна. С другой стороны, симфони делает десятки тысяч разных операций и лог strace, который меньше по объему, удобнее просматривать.
- наконец, есть еще poor man profiling, то есть ручная расстановка по коду команд вывода текущей функции и время, прошедшее от начала запроса. Это конечно может занять много времени.
Если у тебя есть время, я тебе рекомендую попробовать эти варианты. Это даст тебе полезный опыт, который может пригодиться в будущем. Я готов помочь советами если что-то не заработает. Это позволит увидеть, какие именно операции делает код и где тратится время.
Я тебе советую сделать какой-то тестовый контроллер, который просто выводит hello world, чтобы исключить проблемы в твоем коде.
Также, есть несколько вещей, которые можно попробовать сделать без профайлинга:
- включить opcache. Это расширение кеширует скомпилированные скрипты в памяти и избавляет от необходимости компилировать их повторно
- проверить настройки Доктрины, особенно если ты используешь много сущностей. Она в зависимости от настроек может собирать метаданные из кода сущностей и генерироват прокси классы на лету, что увеличивает время выполнения
И почему не добавляется запись в таблицу
I did a roll up/down menu with CSS transitions. It's based on toggling classes with different "max-height". Very simple case, but it doesn't work in a way I expect it to.
The problem is: the menu goes back only after a certain delay, (which is depends on an animation time). Maybe something wrong with my JS, bc it seems like the browser toggles the class with delay (and only then the animation fires).
Here's codepen. You click to open it - it rolls down fast, you click to close it - it waits 2 seconds and only then rolls down: https://codepen.io/anon/pen/dRrwQB
Там не нужно использовать ES6 генераторы, если ты о них. Достаточно написать функцию, возвращающую функцию, которая в свою очередь инкрементирует и возвращает значение из замыкания. Почитай learn.javascript.ru
transition: cubic-bezier(0.17, 0.04, 0.03, 0.94);
В итоге это сделал
100 $key = $_POST['key'];
101 $query="SELECT * FROM posts WHERE text LIKE '$key' OR WHERE title LIKE '$key' ORDER BY id DESC";
102 $result=$pdo->query($query)or die("Запрос не выполнен");
стыдно за тебя
Очень информативно. Обращаю внимание, что в посте указана 102-я строка.
У тебя 2 раза WHERE в запросе. Пиши так: "WHERE text LIKE :key OR title LIKE :key"
Ещё у тебя SQL-инъекция в коде (исправляй срочно) и дурацкий вызов die после $pdo->query
Читай пасты ОПа:
https://github.com/codedokode/pasta/blob/master/student-list.md#Работа-с-базой-данных-из-php
https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
Спасибо, заработало.
Еще вопрос, как вынести подключение к БД за пределы страницы?У меня сейчас код вида
<? соединение с БД ?>
<html>
<? вывод данных из БД?>
но по логике пользователь не должен видеть операции с БД же.
Да, хорошим тоном считается разделять PHP-код от шаблонов: http://web.archive.org/web/20161119062218/http://www.phpinfo.su/articles/practice/shablony_v_php.html
Видно, что ты начинающий и c MVC не знаком, советую почитать/выполнить эту задачу, сам многому научился: https://github.com/codedokode/pasta/blob/master/student-list.md
>>1025450
>>1025433
Зачем вы тут? Не хотите помогать - не засоряйте тред.
Я советую вместо изменения исходного массива не трогать его, а записывать результат в новый массив. Это сделает код проще для понимания, так как у тебя будут отдельно входные, а отдельно выходные данные и выходные не будут влиять на входные.
> попутно считая купюры и отнимая один от ключа до тех пор, пока он не станет равен нулю.
Многократное вычитание - это деление.
Так, твоя идея правильная и называется "жадный алгоритм". Жадный, так как он пытается взять как можно больше купюр каждого номинала.
>>1024904
> public function addDepartament($departament)
Тут нужен тайп-хинт. Вот короткая копипаста:
--------
### Тайп хинты
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ , причем можно указать тип void, значащий, что функция ничего не возвращает (увы, возможность вернуть null пока не реализовали, так что ждем)
--------
Если ты используешь PHP7, то стоит добавить и скалярные (скалярные значения - это не составные значения, то есть не массивы или объекты) тайп-хинты.
> public function deleteWorker($number)
Вот это неудачно спректированная функция. Чтобы удалить работника, надо узнать его номер в приватном списке внутри департамента. Как его узнать? Надо вместо номера передавать самого работника, которого надо уволить. Объект - это сам по себе уникальный идентификатор.
То есть попробуй думать, что объект используется не только в этой задаче, а например в сложной системе учета работников. Удобно ли будет другим разработчикам использовать твой метод, когда им понадобится кого-то уволить?
> $is_Head,
Стиль названия не соответствует другим переменным
> public function getSalary($worker)
Зачем сюда передается worker? Он еще и не используется никак.
Далее, клаcc Analyst почему-то сделан не так, как другие профессии. Почему возможность менять зарплату предусмотрена только для аналитиков? Ну и это неправильно, что ты ради отдельной задачи про антикризисные меры добавляешь какие-то костыли в класс отдельной профессии. Если ты хочешь менять зарплату, то такая возможность должна быть предусмотрена для всех.
Одна из идей ООП - это разделение отвественности, когда у каждого класса есть своя задача, своя зона ответственности. Соответственно антикризисными мерами должен заниматься отдельный класс, а в другие классы помещать код для их реализации не надо. Там должны быть общие, универсальные методы, которые могут быть полезны вообще, а не только для антикризисных мер.
То есть например добавить функцию повышения зарплаты - это можно (логично, зарплата ведь может меняться). Но код повышения зарплаты только для определенной профессии должен быть где-то в другом месте.
Также, ты сделал поле с зарплатой аналитика статическим. А это значит, что в принципе зарплату им нельзя менять индивидуально, только всем аналитикам во всех компаниях сразу.
> class Crisis
Название неудачное, так как класс не представляет собой описание кризиса, а антикризичных мер
Отбор кандидатов на увольнение/повышени лучше сделать так:
- отобрать работников нужной профессии и рангов
- отсортировать в том порядке, в котором нужно увольнять (там вроде ранг используется)
- взять нужное количество с помощью array_slice
Поиск работников нужно как-то унифицировать, а то у тебя там код поиска повторяется.
Код смены главы не стоит смешивать с кодом смены зарплаты так как сложно понять как что работает. Ты пишешь код смены главы внутри цикла по работникам - что же это, ты каждого работника по очереди что ли хочешь сделать главой? Тут логики нет.
Также, логично было сделать отдельный метод в департаменте для замены главы. А ты написал код смены главы где-то снаружи, что по моему не так логично. Это ведь явно область ответственности департамента - управлять списком своих работников и назначением главы.
Я советую вместо изменения исходного массива не трогать его, а записывать результат в новый массив. Это сделает код проще для понимания, так как у тебя будут отдельно входные, а отдельно выходные данные и выходные не будут влиять на входные.
> попутно считая купюры и отнимая один от ключа до тех пор, пока он не станет равен нулю.
Многократное вычитание - это деление.
Так, твоя идея правильная и называется "жадный алгоритм". Жадный, так как он пытается взять как можно больше купюр каждого номинала.
>>1024904
> public function addDepartament($departament)
Тут нужен тайп-хинт. Вот короткая копипаста:
--------
### Тайп хинты
Тайп хинты позволяют указать, что аргумент функции должен быть определенного типа (например быть объектом определенного класса или его наследника). Тайп хинт делает код понятнее (так как видно какого типа переменная) и надежнее (так как PHP не позволит передать что-то неразрешенное и ты сразу увидишь ошибку). Используй их везде.
Мануал: http://php.net/manual/ru/language.oop5.typehinting.php
Обрати внимание, что php7 усовершенствовал систему тайп-хинтов - теперь можно в их качестве указывать примитивные типы вроде int/string, а в php7.1 стало можно указывать тайп-хинт для возвращаемого функцией значения: https://habrahabr.ru/post/267799/ , причем можно указать тип void, значащий, что функция ничего не возвращает (увы, возможность вернуть null пока не реализовали, так что ждем)
--------
Если ты используешь PHP7, то стоит добавить и скалярные (скалярные значения - это не составные значения, то есть не массивы или объекты) тайп-хинты.
> public function deleteWorker($number)
Вот это неудачно спректированная функция. Чтобы удалить работника, надо узнать его номер в приватном списке внутри департамента. Как его узнать? Надо вместо номера передавать самого работника, которого надо уволить. Объект - это сам по себе уникальный идентификатор.
То есть попробуй думать, что объект используется не только в этой задаче, а например в сложной системе учета работников. Удобно ли будет другим разработчикам использовать твой метод, когда им понадобится кого-то уволить?
> $is_Head,
Стиль названия не соответствует другим переменным
> public function getSalary($worker)
Зачем сюда передается worker? Он еще и не используется никак.
Далее, клаcc Analyst почему-то сделан не так, как другие профессии. Почему возможность менять зарплату предусмотрена только для аналитиков? Ну и это неправильно, что ты ради отдельной задачи про антикризисные меры добавляешь какие-то костыли в класс отдельной профессии. Если ты хочешь менять зарплату, то такая возможность должна быть предусмотрена для всех.
Одна из идей ООП - это разделение отвественности, когда у каждого класса есть своя задача, своя зона ответственности. Соответственно антикризисными мерами должен заниматься отдельный класс, а в другие классы помещать код для их реализации не надо. Там должны быть общие, универсальные методы, которые могут быть полезны вообще, а не только для антикризисных мер.
То есть например добавить функцию повышения зарплаты - это можно (логично, зарплата ведь может меняться). Но код повышения зарплаты только для определенной профессии должен быть где-то в другом месте.
Также, ты сделал поле с зарплатой аналитика статическим. А это значит, что в принципе зарплату им нельзя менять индивидуально, только всем аналитикам во всех компаниях сразу.
> class Crisis
Название неудачное, так как класс не представляет собой описание кризиса, а антикризичных мер
Отбор кандидатов на увольнение/повышени лучше сделать так:
- отобрать работников нужной профессии и рангов
- отсортировать в том порядке, в котором нужно увольнять (там вроде ранг используется)
- взять нужное количество с помощью array_slice
Поиск работников нужно как-то унифицировать, а то у тебя там код поиска повторяется.
Код смены главы не стоит смешивать с кодом смены зарплаты так как сложно понять как что работает. Ты пишешь код смены главы внутри цикла по работникам - что же это, ты каждого работника по очереди что ли хочешь сделать главой? Тут логики нет.
Также, логично было сделать отдельный метод в департаменте для замены главы. А ты написал код смены главы где-то снаружи, что по моему не так логично. Это ведь явно область ответственности департамента - управлять списком своих работников и назначением главы.
> зачем нужен интерфейс Итератор?
Чтобы обходить объект в цикле.
> Реализован ли он в современных фреймах?
Да, любой класс коллекций, например коллекции ошибок валидации в symfony/form, коллекции сущностей в доктрине, коллекции HTTP-заголовков и т.д
> нужно ли тратить время на него
Однозначно, у меня даже на собесе про него спрашивали.
Вместо or die нужно включить в PDO режим выброса исключений (PDO::ERRMODE_EXCEPTION).
>>1025430
Обрати внимание на текст "right syntax to use near ..." - это значит, что ошибка в указанном месте, то есть лишний WHERE.
>>1025391
Там нужно использовать переменную в замыкании как счетчик. То есть ты создаешь переменную-счетчик, создаешь новую функцию, и она привязывается к этой переменной и может ее использовать.
Ну если не исправлять код, то ничего и не научишься. Или ты думаешь, другие люди с первого раз безупречный код пишут? А вообще, я тут программированию обучаю, а мотивировать, уж извините, никого не собираюсь. Не нравится - не изучайте.
>>1024516
> На словах ты Лев Толстой - https://ideone.com/S7Xrez
Ок, верно
> Поиск email - https://ideone.com/d2N8d6
Все правильно
> Grammar Nazi - https://ideone.com/925aB2
> '/[,](\\S)/ui', '/[;](\\S)/ui', '/[!](\\S)/ui'
Эти регулярки очень похожи и их надо объединить в одну. То же касается регулярок с жы/шы и зделал/зделаю
> Опечаточник - https://ideone.com/mpNbLd
Твоя программа просто ищет латинские буквы. Но надо искать слова, составленные из букв разных алфавитов. Слова вроде "HELLO" не должны вызывать ошибку.
Итератор - это штука, которая позволяет перебирать содержимое в цикле. Это может быть объект-коллекция (который внутри хранит массив сущностей), но вообще он может и генерировать элементы на лету. Ну например, мы можем сделать объект-итератор, представлющий все записи в таблице, но при этом он их не загружает пока к ним не обратятся. Или мы можем сделать итератор, генерирующий и выдающий простые числа:
foreach ($primeIterator as $number) {
echo "Число: $number\b";
}
Еще итераторы можно комбинировать, используя стандартные или написанные итераторы. Мы можем взять итератор, возвращающий имена файлов в папке, и обернуть его в итератор, который будет брать только файлы с определенным расширением.
Из встроенных итераторов самый популярный - это RecursiveDirectoryIterator, перебирающий файлы в папках с включением подпапок.
Итераторы обычно используют в фреймворках и библиотеках, их редко пишут самостоятельно, больше исопльзуют готовые.
Я советую изучить список встроенных итераторов: http://php.net/manual/ru/spl.iterators.php
Писать итераторы не очень удобно, удобнее сделать функцию-генератор, которая при вызове возвращает итератор: http://php.net/manual/ru/language.generators.overview.php
Да, проблема была с анимацией была именно в том, что CSS анимирует свойство max-height полностью, т.е несмотря на то, что размеры меню 200px, оно анимирует все 900px.
>>>Ну и подсчет высоты сообщений - это явно что-то неправильное. Это нужно для выравнивания сообщений вертикально? Неужели это нельзя было сделать средствами CSS? Задание размеров и расположения элементов через JS работает плохо, может влиять на производительность и работать с задержками.
>> Это нужно сделать отступ сверху, если сообщений слишком мало, и они начинались как бы снизу вверх, а не сверху вниз.
>Это называется "вертикальное выравнивание". Я бы поискал варианты сделать это средствами CSS. Вот что приходит в голову:
>
>- flex, новая технология, которая не везде есть. С ее помощью можно выделить часть экрана под область сообщений, и задать выравнивание блока сообщений по нижнему краю. Ну и не забыть про overflow, чтобы при большом числе сообщений блок не растягивался, а появлялась бы прокрутка. Минус - работает в новых браузерах
>- display: table - работает начиная с ИЕ8 и древних фаерфоксов. Это как flex, только слабее по возможностям и со своими недостатками. Табличное отображение позволяет прижать содержимое ячейки (зоны сообщений) вниз. Тут есть проблемка - чтобы сделать прокрутку, блоку сообщений надо задать высоту, и задать ее в виде 100% (=высоте окна) наверно не получится, значит придется этот момент сделать через JS (определение доступной высоты блока и изменение ее при измнеении размера окна)
>- прижать блок сообщений вниз с помощью абс. поз. Работает тоже везде, и можно задать высоту как 100% от зоны для вывода сообщений (при условии что не используется display: table, так как абс. поз. не работает с элементами таблиц).
>
>Я бы советовал попробовать сделать отдельный пример (примеры) в jsfiddle или аналогичном сервисе, и потестировать его на маленьком и большом числе сообщений (когда должна появляться прокрутка).
>
>Я могу подсказать по CSS, но имея частично работающий код, сделать это проще.
С точки зрения дизайна интерфейса, критично ли будет то, что даже если все сообщения получены, то они всё равно будут прижиматься вниз, оставляя пустое пространство в верху? Я не вижу в этом ничего плохого, но кому-то пустое пространство может показаться не красивым.
https://jsfiddle.net/55khok9f/1/
>>>Ну и подсчет высоты сообщений - это явно что-то неправильное. Это нужно для выравнивания сообщений вертикально? Неужели это нельзя было сделать средствами CSS? Задание размеров и расположения элементов через JS работает плохо, может влиять на производительность и работать с задержками.
>> Это нужно сделать отступ сверху, если сообщений слишком мало, и они начинались как бы снизу вверх, а не сверху вниз.
>Это называется "вертикальное выравнивание". Я бы поискал варианты сделать это средствами CSS. Вот что приходит в голову:
>
>- flex, новая технология, которая не везде есть. С ее помощью можно выделить часть экрана под область сообщений, и задать выравнивание блока сообщений по нижнему краю. Ну и не забыть про overflow, чтобы при большом числе сообщений блок не растягивался, а появлялась бы прокрутка. Минус - работает в новых браузерах
>- display: table - работает начиная с ИЕ8 и древних фаерфоксов. Это как flex, только слабее по возможностям и со своими недостатками. Табличное отображение позволяет прижать содержимое ячейки (зоны сообщений) вниз. Тут есть проблемка - чтобы сделать прокрутку, блоку сообщений надо задать высоту, и задать ее в виде 100% (=высоте окна) наверно не получится, значит придется этот момент сделать через JS (определение доступной высоты блока и изменение ее при измнеении размера окна)
>- прижать блок сообщений вниз с помощью абс. поз. Работает тоже везде, и можно задать высоту как 100% от зоны для вывода сообщений (при условии что не используется display: table, так как абс. поз. не работает с элементами таблиц).
>
>Я бы советовал попробовать сделать отдельный пример (примеры) в jsfiddle или аналогичном сервисе, и потестировать его на маленьком и большом числе сообщений (когда должна появляться прокрутка).
>
>Я могу подсказать по CSS, но имея частично работающий код, сделать это проще.
С точки зрения дизайна интерфейса, критично ли будет то, что даже если все сообщения получены, то они всё равно будут прижиматься вниз, оставляя пустое пространство в верху? Я не вижу в этом ничего плохого, но кому-то пустое пространство может показаться не красивым.
https://jsfiddle.net/55khok9f/1/
Просто учусь формулировать предложения на англ. Спасибо за помощь с вопросом.
- теги можно удалять (значит нужно как использовать unlink)
- при добавлении новых тегов в БД нужно сначала их создать (save), а только потом присоединять к Link
- уже существующие теги не должны создаваться заново, Link нужно связывать с уже существующими тегами
Тут код: https://pastebin.com/56qq7Zdj
Ты зря все это пишешь в контроллере. Лучше сделать в модели функцию updateTags($newTags) и пусть она проверяет что там где изменилось.
Ну а вообще, если лень делать diff то можно просто очищать связь и создавать заново.
https://2ch.hk/pr/res/1020995.html (М)
Спасибо, это уменьшит количество diff'ов. А нормально ли для Active Record делать save() в цикле для новых сущностей? Ещё мой в транзакцию нужно обернуть.
>>1025658
Да, там обновили PHP до 7-й версии, а про расширение mbstring забыли. Как вариант можно использовать https://3v4l.org/
Ещё мне кажется, что этот вопрос за последние треды бьёт все рекорды популярности и может быть стоит об этом написать в ОП-посте. Или что хуже - редактировать сайт на народе, там ведь ссылки на ideone.
Что такое URI?
URL - ссылка, но нееет, это всё детские шалости, ссылкой это называют только не знающие.
URI - унифицированное имя ресурса.
URL - местонахождение ресурса(location)
URN(che za huiny?) - имя ресурса(name)
Так вот URL и URN являются частями URI.
Так блядь в чём смысл? URL - устарело, так? Теперь любые ссылки называть URI?
"http://docs.slimframework.com/request/paths/ "
ЭТО URI? Говорить URL не тру и вообще не правильно?
А вопрос встал ввиду не понимания информации ниже.
Root URI
The root URI is the physical URL path of the directory in which the Slim application is instantiated and run. If a Slim application is instantiated in index.php within the top-most directory of the virtual host’s document root, the root URI will be an empty string. If a Slim application is instantiated and run in index.php within a physical subdirectory of the virtual host’s document root, the root URI will be the path to that subdirectory with a leading slash and without a trailing slash pidor.
(поясните о чём тут)
url описывает МЕСТОНАХОЖДЕНИЕ ресурса.
uri - это не имя, а идентификатор ресурса. он может быть как и url так и urn, так и все в перемешку
url частный случай uri
у одного uri может быть множество url и urn
urn не описывает где лежит ресурс. а url не обязан отражать имя ресурса.
>ЭТО URI? Говорить URL не тру и вообще не правильно?
Человек играющий на скрипке - это музыкант? Говорить, что он скрипач вообще не правильно?
Что не ясного. URI это сам ресурс. Например какая-то книга. Представлена она тебе можеть быть либо ввиде URN (например isbn:NOMER_KNIGI), либо ввиде URL (ссылки туда где эта книга лежит). И то и другое ты потом передаешь нужной программе, и она тебе вытаскивает данные о твоей книге.
URI это АБСТРАКТНЫЙ КЛАСС. URN и URL классы, от него наследующиеся. Инстансов у URL быть не может. Но в то же время каждый инстанс URN или URL - это URI
Ты пример может привести URI? Что значит сам ресурс? Я знаю адрес сайта - foobar.ru, это URL. URL часть URI, значит foobar.ru - это URI? Но URI может иметь несколько URL, и как блядь? Если имя уникально.
Ты дебил, нет?
http://foobar.ru - это как и URL так и URI
А http://www.foobar.ru или https://foobar.ru - это тебе примеры еще пары URL ссылающихся НА ТОТ ЖЕ САМЫЙ ресурс.
При этому у твоего foobar.ru URN может быть каким-нибудь website:foobarcompany
URL показывает где лежит ресурс. URN его уникальное имя в КАКОЙ-ТО СИСТЕМЕ. И то и другое это URI этого ресурса. Это ОБЩЕЕ ТВОЯ СУКА МАТЬ НАЗВАНИЕ . И у любого ресурса может быть миллионы URL или URN
Сука, ты понимаешь, что такое АБСТРАКТНЫЙ КЛАСС - нет?
Вот скажи мне блядь, человек играющий на гитаре - это гитарист или музыкант?
>уникально
Уникальность - это когда по завпросу идентификатора тебе предоставляется один и только один ресурс. При этом у ресурса может быть хуева туча таких уникальных идентификаторов. Если бы один и тот же идентификатор мог описывать разные ресурсы одновременно - вот тогда он не уникален.
URI - это уникальный идентификатор ресурса. Представлен он тебе может либо ввиде URL либо в виде URN. И то и другое это URI.
URI это обобщенное название для URL (обычных ссылок) и URN (всяких странных идентификаторов вроде номера книги или телефона) и может быть каких-то еще других видов ссылок на ресурсы. То есть любой URL или URN является URI.
Вот определения:
URL:
> A Uniform Resource Locator (URL), colloquially termed a web address,[1] is a reference to a web resource that specifies its location on a computer network and a mechanism for retrieving it.
> URLs occur most commonly to reference web pages (http), but are also used for file transfer (ftp), email (mailto), database access (JDBC), and many other applications.
Вот URN:
> In computing, a Uniform Resource Name (URN) is a Uniform Resource Identifier (URI) that uses the urn scheme.
URI:
> A URI is a string of characters used to identify or name a resource.
И вот еще:
> Since RFC 3986[5] in 2005, use of the terms "Uniform Resource Name" and "Uniform Resource Locator" has been deprecated in technical standards in favor of the term Uniform Resource Identifier (URI), which encompasses both
Дальше можно почитать статью https://en.wikipedia.org/wiki/Uniform_Resource_Name и сам RFC, если хочется точных определений.
Хоть авторы и пишут URI, там имеется в виду именно URL, причем не любой, а только URL с использованием протоколов HTTP/HTTPS. Так как это веб-фреймворк.
> А http://www.foobar.ru или https://foobar.ru - это тебе примеры еще пары URL ссылающихся НА ТОТ ЖЕ САМЫЙ ресурс.
Это как раз плохой пример, так как у ресурса должен быть один URI, а не несколько. Адреса http://www.foobar.ru или http://foobar.ru должны вместо отдачи контента редиректить на https://foobar.ru
В твоем манямирке ресурсы должны быть доступны только по одному протоколу и только на одном хосте, ip? А со всех остальных надо редиректить?
Если что, сущность Admin наследуется от RegisteredUser, и есть еще сущность SuperAdmin наследуемая соответственно от Admin.
А еще для Visitor я не создавал таблицу и TDG, гость у меня только куку получает без записи в таблице, так что мы говорим о сущностях Admin, SuperAdmin и RegisteredUser, вот.
Сравнил жопу с пальцем. JS в любом случае придётся учить. С ним на ноде и монге можно ебашить изоморфные приложения без ебли с парсингом. Смысл пхп - разбираться в чужих легаси конюшнях в разных мусохрансках за гроши.
>>1025949
Кажется, что ты переусложнил с четырьмя классами. Что мешает в таблице User держать колонку-дискриминатор, которая будет обозначать тип пользователя? В приложении может быть куча ролей у пользователей и неудобно создавать по классу для каждой роли. Наследование удобно использовать, когда у каждого наследника свой набор колонок в бд / свойств класса (советую почитать про STI, Class TI и Concrete TI).
Я знаю про >STI, Class TI и Concrete TI. Разве не мой случай http://design-pattern.ru/patterns/concrete-table-inheritance.html ?
Хотя наверное не мой. Мой - это когда у перечисленных спортсменов определенные роли на поле.
>
Parse error: syntax error, unexpected T_VARIABLE, expecting T_FUNCTION on line 40
Спасибо, все заработало. Но появилась следующая проблема, как присвоить значение которое возвращает метод класса данной переменной? Вот мой говнокод http://ideone.com/igRnFF
Как раз начинать проект новый буду, собирался на Yii2 но теперь немного сомневаюсь
Есть такое. Я разобрался сам, но всё равно спасибо ещё миллион часов потратил,
чтобы xDebug настроить.
Посмотри как вызывать метод в учебнике, нельзя просто так обращаться к нему как к функции.
>как присвоить значение которое возвращает метод класса данной переменной?
Можешь присвоить в конструкторе или создать отдельный метод setWorkers, например, который будет присваивать свойству workers массив из метода.
Работал ли кто с композитными формами (nested forms)? Такая фича точно есть симфони, но нечто подобное хочу реализовать Yii. Суть в чем, что у меня есть форма для регистрации пользователя, также используется точно такая же форма для регистрации пользователя от имени админа, вполне возможно что впоследствии нечто подобное нужно будет использовать для регистрации пользователя через апи. В общем, чтобы не плодить кучу разных моделей форм и дублировать код, хочу использовать как раз композитные формы, и в экшенах всех контроллеров как раз везде подставлять эту композитную форму, что было бы крайне удобно.
В общем, в чем проблема. Я понимаю, что композитная форма имеется в виду форма, а в нее внутри формы (т.е. типичный такой пример -- корзина интернет-магазина), но у меня несколько другой случай. У меня практически идентичные формы, которые должны меняться от ситуации к ситуации, в зависимости от того какой контроллер вызывает. И как лучше всего это сделать? Кто мог бы посоветовать? Хотел похимичить с __call, и вроде как через это и нужно работать, но пока не очень выходит, и мне кажется, что это далеко не идеальное решение. Если кто-то подобное решал, то рад бы был подсмотреть код, ну или хотя бы в общих чертах опишите, что нужно сделать, собственно.
>Сравнил жопу с пальцем
С хяльцем. Уже несколько лет слышу про ноду - убийцу ПХП, да чет все никак не не взлетает. Теперь вот стал все чаще слышать по Go, а с нодой все как-то тише и тише. При этом пхп сколько занимал информационного пространства - столько и занимает если не больше. Ах да, пхп узко-направленный язык, уступающий модным разваливающимся свистоперделкам, срок жизни которых - несколько лет, после чего прийдет новая хайпо-развалюха.
>мусохрансках за гроши
а с го и нодой, ты хуй работу найдешь и если найдешь, то срок актуальности твоих знаний и умений - 2-3 года, после чего придется учить новую революционную все-убийцу, на ближайшие 2 года.
>да чет все никак не не взлетает.
Это ты так решил?
>а с го и нодой, ты хуй работу найдешь
Тож сам так решил?))Может стоит зайти хотя бы на hh и увидеть 900~ вакансий?
>то срок актуальности твоих знаний и умений - 2-3 года
И еще раз, ecma тебе в любом случае придется уметь.
>сам так решил?))
ага)))))
>увидеть 900~ вакансий
и эти 900 высосаных из пальца и возникших на волне хайпа вакансии количество которых не сравнится с пхп уже меняются на то же количество но теперь для го, а через пару лет будут актуальны для новой йобы. А для пхп как было дохуя, так дохуя остается и растет, причем вакансии как для низкооплачиваемых макак, так и высокооплачиваемые для гуру господ. И если ты зеленый, то ты можешь не ссаться, что через 2 года твои знания никому нахуй не нужны будут, а спокойно развиваться.
>ecma тебе в любом случае придется уметь
Хуекма. Одна из особенностей джаваскрипта в том, что ты можешь писать на нем, его не зная, т.к. изучение одного из 100500 жс фреймворков сродни изучению нового языка.
И нахуя мне нужна нода, чтобы использовать жквери?
>и эти 900 высосаных из пальца и возникших на волне хайпа вакансии
А какой процент из этого является "знать пых 3 и 5, терпение и умение разбираться в чужом коде"?
Или "мы слышали что на пхп делают сайтики, но нам на самом деле нам абсолютно похуй чем ты там занимаешься, лишь бы было"
>т.к. изучение одного из 100500 жс фреймворков сродни изучению нового языка.
Лол
>Одна из особенностей джаваскрипта в том, что ты можешь писать на нем, его не зная
>чтобы использовать жквери?
>Лол
Треснул квадратно-гнездовой шаблон? Бывает
>А какой процент из этого...
И, что ты хотел этим сказать, не пойму? точно также не пойму как необходимость знания екма связывает изучение ноды для того, чтобы уметь использовать жквери?
>И, что ты хотел этим сказать, не пойму?
Макака не смогла в контекст и зависла?
>жырквери
>кому-то про квадраты-гнёзда, да шаблоны заливает.
хайпошкольник порвался
пруф
Одно другому, тащем-та, не мешает. Бадушники тому — живой пример.
А есть статистика по пыхозарплатам без учета битриксов и прочих макак из уэб-студий?
https://www.codewars.com/kata/remove-first-and-last-character/
https://m.habrahabr.ru/company/zfort/blog/333458/
почему нет? Есть, вон нода, го. Скоро пхп пизда
Что можно сделать после успешной отправки сообщения?
Можно обновить все сообщения, но сообщения и так обновляются каждые пол секунды. Как-то не хочется оставлять пустую функцию. Или её можно не писать?
https://arhivach.org/thread/261841/#1000396
>Ты не обрабатываешь ошибки. Видимо, уроки, которые ты читал, упускают такие важные вещи. Вот тебе тогда мои маленькие советы про использование аякса: https://github.com/codedokode/pasta/blob/master/js/ajax.md
https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L59-L69
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L85-L92
Стоит ли так выборочно обрабатывать ошибки? Для пользователя достаточно вывести ошибку соединения, а для разработчиков выбросить в консоль статус и текст ошибки.
Почему у меня не вбрасываются эти ошибки (ошибки не появляются в консоле)? Это из-за асинхронного кода?
https://arhivach.org/thread/266631/#1010744
>> Кстати, это нормально делать перевод на новую строку в цикле https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L280-L284 ?
>Это какие-то кривые костыли. Получается, логика отображения разбросана между шаблоном и JS кодом. Мы ведь в PHP не пытаемся так делать после генерации HTML из шаблона? И тут не надо. Наверняка там есть какие-нибудь хелперы для таких преобразований. В чем проблема сделать какой-нибудь хелпер для преобразования текстов сообщений?
К сожалению, у меня не получилось найти в ejs аналог функции nl2br и при этом чтобы экранировались тэги. В таком случае, будет приемлемым оставить этот костыль?
Или лучше, можете посоветовать какой-нибудь шаблонизатор который справиться с этой задачей?
И что если я захочу не экранировать определённые тэги? Должено быть какое-то решение чтобы справиться с этими задачами.
https://github.com/someApprentice/chat/blob/master/src/Controller/ConversationController.php#L78-L115
Это нормально, что у меня такая простыня с обработкой ошибок?
https://arhivach.org/thread/261841/#1000396
>Также, некоторые разработчики активно используют возможности HTTP (дополнительные заголовки, методы вроде PUT/DELETE, коды ответов), а некоторые не используют.
>Также, перед проектированием АПИ, советую почитать про REST и HATEOS (и далее, стандарт про шаблоны URL https://tools.ietf.org/html/rfc6570 ), но тут конечно есть разные мнения, ну к примеру в иделогии REST одним запросом нельзя получить несколько несвязанных массивов данных, а HATEOS раздувает размер ответа.
Я плохо понял что такое REST. Это просто архитектура которая позволяет обрабатывать запросы с методами вроде PUT\DELETE?
Я пока не могу придумать для чего использовать такие методы.
https://arhivach.org/thread/266631/#1010325
>Пересоздавать полный список сообщений неэффективно.
Я никак не могу придумать как выводить только новые сообщения. Определенно, нужен setTimeout\setInterval чтобы постоянно обновлять данные с сервера, но как при этом выводить только те сообщения которые ещё не выведены в шаблон?
https://github.com/someApprentice/chat/blob/master/src/Model/Database/MessageGateway.php#L25
Поскольку, я теперь вывожу сообщения за определённый период времени, то если за этот промежуток не было сообщений, при открытии диалога выведиться пустое окно сообщений из-за чего вытекает баг с автоматической подрузкой более старых сообщений, из-за того что отсутвует скролл блока сообщений. Это можно исправить увеличивая отрезок времени и повторном обращении к БД, до тех пор пока не получим нужное количество сообщений:
$count = $db->getMessagesCount();
$offset = 1;
if ($count > 10) {
while(count($messages) < 10) {
$offset++;
$messages = $db->getMessages(..., $offset);
}
}
Не будет ли это лишней нагрузкой на БД?
У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори. Я уже делаю что-то подобное при получении более старых сообщениях (при выключенном js):
https://github.com/someApprentice/chat/blob/master/templates/chat.phtml#L24
><a ... href="conversation.php? ... #message-ID">Получить больше сообщений</a>
https://github.com/someApprentice/chat/blob/master/templates/chat.phtml#L32
><div id="message-ID ... class="message">
Точно так же можно сделать в ссылке контакта.
Но для этого нужно сделать несколько лишних запросов к БД:
$contacts = $db->getContacts();
$c = array();
foreach ($contacts as $contact) {
$lastMessage = $db->getLastMessage(...);
$c[] = array(
'contact' => $contact,
'lastMessage' => $lastMessage
);
}
Я согласен, что на первый взгляд идея может показаться нелепой, но примерно такой же код придётся делать, если нужно будет отсортировать контакты по последним сообщениям.
Опять же, не создаст ли это большую нагрузку на БД? Учитывая, что с включенным js, при сортировке по последним сообщениям, обновление контактов будет происходить каждую секунду.
https://github.com/someApprentice/chat/blob/master/src/Controller/AuthController.php#L101-L103
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L217
Не подвергаю ли я пользователей опасности, открывая кукисы для js?
Просто при открытии диалога нет возможности получить токен. Если только не спрятать его где-то на странице. Я сомневаюсь что это будет правильным решением, но с другой стороны не вижу никакой проблемы. Как лучше поступить?
У меня есть переменные, которые пишутся ни как camelCase или snake_case, например moremessages. Я знаю, что это плохой плохой вариант, но мне он кажется вполне читабельным. Лучше будет переимновать?
Что можно сделать после успешной отправки сообщения?
Можно обновить все сообщения, но сообщения и так обновляются каждые пол секунды. Как-то не хочется оставлять пустую функцию. Или её можно не писать?
https://arhivach.org/thread/261841/#1000396
>Ты не обрабатываешь ошибки. Видимо, уроки, которые ты читал, упускают такие важные вещи. Вот тебе тогда мои маленькие советы про использование аякса: https://github.com/codedokode/pasta/blob/master/js/ajax.md
https://github.com/someApprentice/chat/blob/master/public/js/chat.js#L59-L69
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L85-L92
Стоит ли так выборочно обрабатывать ошибки? Для пользователя достаточно вывести ошибку соединения, а для разработчиков выбросить в консоль статус и текст ошибки.
Почему у меня не вбрасываются эти ошибки (ошибки не появляются в консоле)? Это из-за асинхронного кода?
https://arhivach.org/thread/266631/#1010744
>> Кстати, это нормально делать перевод на новую строку в цикле https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L280-L284 ?
>Это какие-то кривые костыли. Получается, логика отображения разбросана между шаблоном и JS кодом. Мы ведь в PHP не пытаемся так делать после генерации HTML из шаблона? И тут не надо. Наверняка там есть какие-нибудь хелперы для таких преобразований. В чем проблема сделать какой-нибудь хелпер для преобразования текстов сообщений?
К сожалению, у меня не получилось найти в ejs аналог функции nl2br и при этом чтобы экранировались тэги. В таком случае, будет приемлемым оставить этот костыль?
Или лучше, можете посоветовать какой-нибудь шаблонизатор который справиться с этой задачей?
И что если я захочу не экранировать определённые тэги? Должено быть какое-то решение чтобы справиться с этими задачами.
https://github.com/someApprentice/chat/blob/master/src/Controller/ConversationController.php#L78-L115
Это нормально, что у меня такая простыня с обработкой ошибок?
https://arhivach.org/thread/261841/#1000396
>Также, некоторые разработчики активно используют возможности HTTP (дополнительные заголовки, методы вроде PUT/DELETE, коды ответов), а некоторые не используют.
>Также, перед проектированием АПИ, советую почитать про REST и HATEOS (и далее, стандарт про шаблоны URL https://tools.ietf.org/html/rfc6570 ), но тут конечно есть разные мнения, ну к примеру в иделогии REST одним запросом нельзя получить несколько несвязанных массивов данных, а HATEOS раздувает размер ответа.
Я плохо понял что такое REST. Это просто архитектура которая позволяет обрабатывать запросы с методами вроде PUT\DELETE?
Я пока не могу придумать для чего использовать такие методы.
https://arhivach.org/thread/266631/#1010325
>Пересоздавать полный список сообщений неэффективно.
Я никак не могу придумать как выводить только новые сообщения. Определенно, нужен setTimeout\setInterval чтобы постоянно обновлять данные с сервера, но как при этом выводить только те сообщения которые ещё не выведены в шаблон?
https://github.com/someApprentice/chat/blob/master/src/Model/Database/MessageGateway.php#L25
Поскольку, я теперь вывожу сообщения за определённый период времени, то если за этот промежуток не было сообщений, при открытии диалога выведиться пустое окно сообщений из-за чего вытекает баг с автоматической подрузкой более старых сообщений, из-за того что отсутвует скролл блока сообщений. Это можно исправить увеличивая отрезок времени и повторном обращении к БД, до тех пор пока не получим нужное количество сообщений:
$count = $db->getMessagesCount();
$offset = 1;
if ($count > 10) {
while(count($messages) < 10) {
$offset++;
$messages = $db->getMessages(..., $offset);
}
}
Не будет ли это лишней нагрузкой на БД?
У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори. Я уже делаю что-то подобное при получении более старых сообщениях (при выключенном js):
https://github.com/someApprentice/chat/blob/master/templates/chat.phtml#L24
><a ... href="conversation.php? ... #message-ID">Получить больше сообщений</a>
https://github.com/someApprentice/chat/blob/master/templates/chat.phtml#L32
><div id="message-ID ... class="message">
Точно так же можно сделать в ссылке контакта.
Но для этого нужно сделать несколько лишних запросов к БД:
$contacts = $db->getContacts();
$c = array();
foreach ($contacts as $contact) {
$lastMessage = $db->getLastMessage(...);
$c[] = array(
'contact' => $contact,
'lastMessage' => $lastMessage
);
}
Я согласен, что на первый взгляд идея может показаться нелепой, но примерно такой же код придётся делать, если нужно будет отсортировать контакты по последним сообщениям.
Опять же, не создаст ли это большую нагрузку на БД? Учитывая, что с включенным js, при сортировке по последним сообщениям, обновление контактов будет происходить каждую секунду.
https://github.com/someApprentice/chat/blob/master/src/Controller/AuthController.php#L101-L103
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L217
Не подвергаю ли я пользователей опасности, открывая кукисы для js?
Просто при открытии диалога нет возможности получить токен. Если только не спрятать его где-то на странице. Я сомневаюсь что это будет правильным решением, но с другой стороны не вижу никакой проблемы. Как лучше поступить?
У меня есть переменные, которые пишутся ни как camelCase или snake_case, например moremessages. Я знаю, что это плохой плохой вариант, но мне он кажется вполне читабельным. Лучше будет переимновать?
З.Ы. А зачем в эхо выделять переменные фигурными скобками?
>$example = function () use ($variable) { ... }
В мануале http://php.net/manual/ru/functions.anonymous.php
не понял что значит этот use, и когда надо и не надо его употреблять.
Объясните, пожалуйста, что значит символ "|"? Это оператор? Гугл не помог. Я нашел только || - логическое ИЛИ.
Вот пример такого сайта: https://goo.gl/n7bfuT Сократил, потому что макака-пидор.
Чтобы разобраться в этой теме, придется почитать про двоичные числа. Любое число можно представить не только в обычной (10-ной) системе счисления, но и в двоичной. Например, 19 в десятичной = 10011 в двоичной.
https://ru.wikipedia.org/wiki/Двоичная_система_счисления
Двоичная система используется потому, что внутри компьютера все числа представлены как раз в двоичном виде. Например, если в ячейке памяти есть электрический заряд, то это обозначает 1, а если нет - то там хранится 0. Одно такое значение - 0 или 1 - называется бит. Используя несколько ячеек, мы можем с помощью этих битов кодировать произвольные числа. То есть двоичная система "родная" для компьютера и внутри числа представлены и обрабатываются в этой системе.
С числами в двоичной форме кроме обычных математических операций можно делать битовые операции вроде И или ИЛИ: https://ru.wikipedia.org/wiki/Битовые_операции
http://php.net/manual/ru/language.operators.bitwise.php
Если нам нужно как-то закодировать набор опций, каждая из которых может быть включена или выключена, мы можем использовать двоичные числа. То есть договориться, что например последний разряд в числе обозначает одну опцию (OPTION1 = 00001), предпоследний - другую (OPTION2 = 000010).
Тогда с помощью операции ИЛИ мы можем объединять эти опции: OPTION1 | OPTION2 = 0000011
В общем-то константы вроде PDO::FETCH_CLASS - это числа (можно проверить echo или var_dump), каждое из которых содержит одну единицу в двоичном виде, а с помощью операции ИЛИ их объединяют.
Такие опции еще называют "флаги" (по аналогии с флагами, используемыми для передачи сигналов визуально на кораблях). Вообще, эта система кодирования идет с древних времен, когда компьютеры были медленные и у них было мало памяти, и хотели ее использовать максимально эффективно (используя ровно 1 бит на одну опцию). Сейчас конечно это не так принципиально, но для флагов двоичные числа как раз хорошо подходят.
Чтобы проверить и закрепить знания, реши задачку:
- сделай набор из нескольких констант, каждая из которых будет представлять какую-то опцию, которая кодируется с помощью двоичных флагов (то есть константа хранит число, в двоичном виде содержащее ровно одну единицу)
- сделай функцию setBit, которая принимает на вход число и опцию, и возвращает число где установлен в единицу соответствующий опции бит
- сделай функцию clearBit, которая принимает на вход число и опцию, и возращает число, где соответствующий опции бит сброшен
- сделай функцию toggleBit, которая принимает на вход число и опцию и меняет соответствующий бит в числе на противоположный
- сделай функцию testBit, которая принимает на вход число и одну опцию и возвращает true/false в зависимости от того, включен в этом числе соответствующий флаг или нет
- сделай функцию countBits, которая принимает на вход число и возвращает число единиц в его двоичном представлении
Пример использования:
const OPTION_A= ...;
const OPTION_B = ...;
const OPTION_C = ...;
$flags = 0;
$flags = setBit($flags, OPTION_A);
$flags = setBit($flags, OPTION_B);
var_dump(testBit($flags, OPTION_A)); // true
var_dump(testBit($flags, OPTION_C)); // false
$flags = clearBit($flags, OPTION_A);
var_dump(testBit($flags, OPTION_A)); // false
var_dump(testBit($flags, OPTION_B)); // true
var_dump(countBits($flags)); // 1
Если что-то непонятно, уточняй.
Чтобы разобраться в этой теме, придется почитать про двоичные числа. Любое число можно представить не только в обычной (10-ной) системе счисления, но и в двоичной. Например, 19 в десятичной = 10011 в двоичной.
https://ru.wikipedia.org/wiki/Двоичная_система_счисления
Двоичная система используется потому, что внутри компьютера все числа представлены как раз в двоичном виде. Например, если в ячейке памяти есть электрический заряд, то это обозначает 1, а если нет - то там хранится 0. Одно такое значение - 0 или 1 - называется бит. Используя несколько ячеек, мы можем с помощью этих битов кодировать произвольные числа. То есть двоичная система "родная" для компьютера и внутри числа представлены и обрабатываются в этой системе.
С числами в двоичной форме кроме обычных математических операций можно делать битовые операции вроде И или ИЛИ: https://ru.wikipedia.org/wiki/Битовые_операции
http://php.net/manual/ru/language.operators.bitwise.php
Если нам нужно как-то закодировать набор опций, каждая из которых может быть включена или выключена, мы можем использовать двоичные числа. То есть договориться, что например последний разряд в числе обозначает одну опцию (OPTION1 = 00001), предпоследний - другую (OPTION2 = 000010).
Тогда с помощью операции ИЛИ мы можем объединять эти опции: OPTION1 | OPTION2 = 0000011
В общем-то константы вроде PDO::FETCH_CLASS - это числа (можно проверить echo или var_dump), каждое из которых содержит одну единицу в двоичном виде, а с помощью операции ИЛИ их объединяют.
Такие опции еще называют "флаги" (по аналогии с флагами, используемыми для передачи сигналов визуально на кораблях). Вообще, эта система кодирования идет с древних времен, когда компьютеры были медленные и у них было мало памяти, и хотели ее использовать максимально эффективно (используя ровно 1 бит на одну опцию). Сейчас конечно это не так принципиально, но для флагов двоичные числа как раз хорошо подходят.
Чтобы проверить и закрепить знания, реши задачку:
- сделай набор из нескольких констант, каждая из которых будет представлять какую-то опцию, которая кодируется с помощью двоичных флагов (то есть константа хранит число, в двоичном виде содержащее ровно одну единицу)
- сделай функцию setBit, которая принимает на вход число и опцию, и возвращает число где установлен в единицу соответствующий опции бит
- сделай функцию clearBit, которая принимает на вход число и опцию, и возращает число, где соответствующий опции бит сброшен
- сделай функцию toggleBit, которая принимает на вход число и опцию и меняет соответствующий бит в числе на противоположный
- сделай функцию testBit, которая принимает на вход число и одну опцию и возвращает true/false в зависимости от того, включен в этом числе соответствующий флаг или нет
- сделай функцию countBits, которая принимает на вход число и возвращает число единиц в его двоичном представлении
Пример использования:
const OPTION_A= ...;
const OPTION_B = ...;
const OPTION_C = ...;
$flags = 0;
$flags = setBit($flags, OPTION_A);
$flags = setBit($flags, OPTION_B);
var_dump(testBit($flags, OPTION_A)); // true
var_dump(testBit($flags, OPTION_C)); // false
$flags = clearBit($flags, OPTION_A);
var_dump(testBit($flags, OPTION_A)); // false
var_dump(testBit($flags, OPTION_B)); // true
var_dump(countBits($flags)); // 1
Если что-то непонятно, уточняй.
Если шапка одинаковая, зачем ее копипастить, когда можно просто вынести ее в отдельный файл? И объединить шапку с содержимым используя например PHP (это 2 строчки кода)?
Забирает себе значение $variable на время определения функции для дальнейшего использования. То есть если ты создал функцию, а $variable не определил ещё, то будет у твоей функции $variable будет всегда NULL. Иначе нужно &$variable писать, чтобы по ссылке передавало. Тогда берёт значение на момент выполнения.
Если ты вызываешь функцию sequence без указания step или start то они должны быть равны 1 и 0 соответственно.
У меня почему-то в голове переклинило, что требования были к возвращаемой функции, и моск завис.
Да, там вообще не очень легко разобраться, так как тут функция возвращает другую функцию и не очень понятно, как их различать.
Как не обосраться в том случае, если какой нибудь мамкин мистер робот решит взломать твой сайт?
В данном случае это примерно такой же вопрос, а почему нет замены unix для серверных машин, потому что 80% на этом работает. Хорошо это или плохо -- вопрос уже сугубо субъективных частностей.
Чем отличается какой нибудь питон/руби/ещё что то фреймворк от пхп?
Лёгкостью? А в чем эта легкость заключается?
сорре за тупой вопрос
https://arhivach.org/thread/261841/#1000397
>Насчет проектирования БД - там тоже много тонкостей есть, можно делать нормальзованную схему, но лучше денормализовывать ради повышения производительности. Ну например, возьмем то же сообщение. Можно хранить его в одном экземпляре, а можно в двух - в inbox получателя и в outbox отправителя. Это может облегчить выборку последних N сообщений, так как твой запрос с OR вряд ли хорошо ложится на индексы (вдобавок у тебя еще и сортировки там нет).
Безусловно, нужно хранить сообщения в нескольких экземплярах для отправителя и для получателя, чтобы в дальнейшем было удобно шифровать их для каждого пользователя соответственно. Но я не понимаю как хранить ID сообщений - получается что для каждого пользователя оно теперь будет своё. Из этого вытекает, что нельзя будет как-то преобразовывать эти сообщения т.е. редактировать или удалять. В принципе от этой идеи можно оказаться, как это сделано в популярных мессенджерах А я всё думал, почему же они это не сделали, просто странно иметь разные ID.
Хотя, можно сделать отдельную колонку, которая не имеет PRIMARY_KEY, и заполнять ID как-то программно.
Думаю лучше отложить пока идею с редактированием\удалением.
Такой же вопрос, и с inbox и outbox - в них те же самые сообщения будут иметь разные ID. Это неизбежно делать отдельную колонку и генерировать ID программно?
Или я не правильно понял структуру этих таблиц?
Никак не могу сформулировать структуру при реализации конференций... Попробую представить это здесь
Conferences
id
tete-a-tete //true or false (приватные переписки тоже будут представлены как конференции из двух человек для унификации кода)
Participants
id //Не уверен что от этой колонки будет толк, обычно всегда делают id
conferenceID
userID
Contacts
id
userID
conferenceID
Inbox
id
conferenceID
userID // ID пользователя которому принадлежит ящик
messageID
authorID
content
...
Outbox
id
conferenceID
userID // ID пользователя которому принадлежит ящик
messageID
authorID
content
...
Соответственно получение сообщений происходит одним запросом SELECT FROM Inbox WHERE conferenceID = :conferenceID AND userID = :userID UNION SELECT FROM Outbox WHERE conferenceID = :conferenceID AND userID = :userID
Вроде должно быть так?
----
Забыл ещё спросить в предыдущем посте
Когда при выводе нового элемента, мы устанавливаем на него обработчик, то мы его не переназначаем, а добавляем новый, и каждый раз когда происходит это событие, обработчик выполняется столько раз, сколько мы выводили элемент
https://jsfiddle.net/jsqt57hz/
MVC style:
https://jsfiddle.net/hmgz7200/
Чтобы это пификсить нужно убрать с элемента обработчик функцией .off()
//Странно что не получилось написать $('body).off('submit', form, handleFormSubmit), как в примере мануала
https://jsfiddle.net/jsqt57hz/1/
Я всё правильно делаю?
>>1027651
>У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори. Я уже делаю что-то подобное при получении более старых сообщениях (при выключенном js):
>Но для этого нужно сделать несколько лишних запросов к БД:
Это должно быть сделано с помощью функций JOIN и GROUP:
SELECT Contacts.userID, Messages.messageID as lastMessage
FROM Contacts
INNER JOIN Messages ON Contacts.userID= Messages.userID
GROUP BY Contacts.userID
ORDER BY Messages.date DESC
Простите что трачу ваше время. Мне действительно очень очень жаль так поступать. Надеюсь у меня всё получиться чтобы всё было не зря.
https://arhivach.org/thread/261841/#1000397
>Насчет проектирования БД - там тоже много тонкостей есть, можно делать нормальзованную схему, но лучше денормализовывать ради повышения производительности. Ну например, возьмем то же сообщение. Можно хранить его в одном экземпляре, а можно в двух - в inbox получателя и в outbox отправителя. Это может облегчить выборку последних N сообщений, так как твой запрос с OR вряд ли хорошо ложится на индексы (вдобавок у тебя еще и сортировки там нет).
Безусловно, нужно хранить сообщения в нескольких экземплярах для отправителя и для получателя, чтобы в дальнейшем было удобно шифровать их для каждого пользователя соответственно. Но я не понимаю как хранить ID сообщений - получается что для каждого пользователя оно теперь будет своё. Из этого вытекает, что нельзя будет как-то преобразовывать эти сообщения т.е. редактировать или удалять. В принципе от этой идеи можно оказаться, как это сделано в популярных мессенджерах А я всё думал, почему же они это не сделали, просто странно иметь разные ID.
Хотя, можно сделать отдельную колонку, которая не имеет PRIMARY_KEY, и заполнять ID как-то программно.
Думаю лучше отложить пока идею с редактированием\удалением.
Такой же вопрос, и с inbox и outbox - в них те же самые сообщения будут иметь разные ID. Это неизбежно делать отдельную колонку и генерировать ID программно?
Или я не правильно понял структуру этих таблиц?
Никак не могу сформулировать структуру при реализации конференций... Попробую представить это здесь
Conferences
id
tete-a-tete //true or false (приватные переписки тоже будут представлены как конференции из двух человек для унификации кода)
Participants
id //Не уверен что от этой колонки будет толк, обычно всегда делают id
conferenceID
userID
Contacts
id
userID
conferenceID
Inbox
id
conferenceID
userID // ID пользователя которому принадлежит ящик
messageID
authorID
content
...
Outbox
id
conferenceID
userID // ID пользователя которому принадлежит ящик
messageID
authorID
content
...
Соответственно получение сообщений происходит одним запросом SELECT FROM Inbox WHERE conferenceID = :conferenceID AND userID = :userID UNION SELECT FROM Outbox WHERE conferenceID = :conferenceID AND userID = :userID
Вроде должно быть так?
----
Забыл ещё спросить в предыдущем посте
Когда при выводе нового элемента, мы устанавливаем на него обработчик, то мы его не переназначаем, а добавляем новый, и каждый раз когда происходит это событие, обработчик выполняется столько раз, сколько мы выводили элемент
https://jsfiddle.net/jsqt57hz/
MVC style:
https://jsfiddle.net/hmgz7200/
Чтобы это пификсить нужно убрать с элемента обработчик функцией .off()
//Странно что не получилось написать $('body).off('submit', form, handleFormSubmit), как в примере мануала
https://jsfiddle.net/jsqt57hz/1/
Я всё правильно делаю?
>>1027651
>У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори. Я уже делаю что-то подобное при получении более старых сообщениях (при выключенном js):
>Но для этого нужно сделать несколько лишних запросов к БД:
Это должно быть сделано с помощью функций JOIN и GROUP:
SELECT Contacts.userID, Messages.messageID as lastMessage
FROM Contacts
INNER JOIN Messages ON Contacts.userID= Messages.userID
GROUP BY Contacts.userID
ORDER BY Messages.date DESC
Простите что трачу ваше время. Мне действительно очень очень жаль так поступать. Надеюсь у меня всё получиться чтобы всё было не зря.
Обратись в баз данных тред, может там помогут.
Хммм, феласаф
Ответ на любой вопрос это же google!
5.5 Давай сделаем программу, отвечающую на любой вопрос. Для этого создадим массив с возможными вариантами ответов, сгенерируем случайное число и возьмем из массива элемент с таким номером.
Подсказка: здесь тебе могла бы помочь функция array_rand()
http://ideone.com/eyM8V0
главная проблема не выводится значение массива
>Тогда берёт значение на момент выполнения
Как это понять? Если у меня выше по коду например вообще нет такой переменной, что будет взято в &$variable?
NULL же.
>Чем отличается какой нибудь питон/руби/ещё что то фреймворк от пхп?
>Лёгкостью? А в чем эта легкость заключается?
>сорре за тупой вопрос
Да ничем, если так подумать. Большинство из этих фреймворков MVC, поэтому очень друг на друга похожи. В той или иной степени реализуют парадигму ООП. В общем, это вопрос вкусов, хотя где-то в виду хайлоада будет более применим какой-нибудь руби или питон, нежели пхп. Но не более того.
Дефисы у меня работали. Первая же ссылка в гугле подтверждает: https://github.com/yiisoft/yii2/issues/493
>>1028469
> главная проблема не выводится значение массива
В документации array_rand написано "returns the key (or keys) of the random entries.", то есть функция возвращает ключ (индекс элемента), а не значение: http://php.net/manual/en/function.array-rand.php
Тебе нужно обратиться к элементу массива под этим новым случайным индексом, тогда получишь значение.
>>1027942
В PHP, в отличии от JS, функция не может обращаться к внешним переменным, то есть к тем, которые существуют за пределами этой функции. Такой код вызовет ошибку:
$n = 3;
array_filter([1,2,3,4,5], function ($el) { return $el > $n; });
PHP скажет, что $n не определена внутри функции.
А с этим кодом всё ок:
$n = 3;
array_filter([1,2,3,4,5], function ($el) use ($n) { return $el > $n; });
>>1028470
Тебе же никто не запрещает просто взять и проверить.
>>1027969
Интересные задачи, нужно порешать.
use описан тут http://php.net/manual/ru/functions.anonymous.php
Он позволяет передать копию значения переменной снаружи внутрь анонимной функции (по умолчанию в функции доступны только созданные внутри нее переменные). Если использовать &$foo вместо $foo, то передается не копия значения, а ссылка на саму переменную, и код внутри функции может менять эту переменную.
>>1028199
Вообще, я не знаю, как "правильно" сделать схему хранения сообщений, потому давай сравним варианты.
Одно мне пока понятно - чаты и диалоги лучше делать одинаковым способом, то есть представить диалог 2 пользователей как чат из 2 участников.
Первый вариант - сделать у каждого пользователя списки входящих и исходящих сообщений (по аналогии с почтовым ящиком), и помещать копии сообщения как отправителю, так и получателю. При этом каждый может независимо управлять своей историей сообщений, например, очищать ее. Для чатов сообщение придется копировать многократно.
При этом, чтобы связать сообщения, можно сделать какой-нибудь добавочный id. Можно например сделать таблицу сообщений (где и будет этот id), и отдельно таблицу, которая хранит копию сообщения для конкретного получателя.
Шифрование проблем никаких не вызывает: отправитель шифрует сообщение открытым ключом пользователя и помещает его в "входящие". В чате отправитель (или сервер) делает N копий, для каждого участника. Новый участник чата не видит старые сообщения.
Другой вариант - сделать сущность "беседа" (чат между 2 или более пользователями) и прикреплять каждое сообщение к "беседе". В этом случае у нас имеется одна копия сообщения. Очистку истории (только с одной стороны) можно реализовать добавлением поля вроде "время, начиная с которого видны сообщения". Это позволяет одному пользователю в диалоге или чате очистить историю на своей стороне, не трогая историю других участников. Также это позволяет новым присоединившимся к чату пользователям не видеть старые сообщения.
Конечно, есть еще вариант отказаться от возможности индивидально чистить историю и сделать так, что любой участник беседы может удалить сообщения в ней.
Для реализации шифрования нам придется сделать ключ "беседы", так, что у всех участников беседы есть приватный ключ для расшифровки сообщения. То есть когда создается новый диалог, участники сообща генерируют приватный ключ, открытый ключ, и шифруют сообщения открытым ключом при отправке в беседу. При этом надо рассмотреть такие сценарии:
- из чата вышел участник - нужен новый ключ для новых сообщений, чтобы он их не мог расшифровать
- в чат добавился участник - нужен новый ключ, чтобы он не видел более старые сообщения
- пользователь потерял пароль/устройство и приватный ключ для расшифровки входящих сообщений - что делать? наверно, генерировать новый ключ
То есть в одной беседе может быть использоваться несколько ключей в разные промежутки времени и пользователь должен хранить их копии, если хочет читать сообщения в ней. И тогда нужна какая-то таблица для хранения информации, какой пользователь за какой промежуток времени видел беседу и какой ключ использовал.
Так как ключей много, компрометация одного из них не дает доступа ко всем сообщениям, а только к сообщениям за один период времени в одной беседе. Но где-то все эти ключи бесед надо хранить - и если мы хотим доступ с нескольких устройств, то ключи придется хранить на сервере (зашифрованные главным ключом).
В общем, есть 2 варианта, предлагаю сравнить их преимущества и недостатки.
Кстати, кроме шифрования сообщений нужно еще предусмотреть подпись - чтобы получатель мог убедиться, что оно отправлено именно отправителем.
Также, вопрос еще, где хранить ключи. Можно иметь единый ключ пользователя, хранящийся на сервере и зашифрованный паролем (устройства скачивает шифрованный ключ и расшифровывает локально). Либо же можно для каждого устройства иметь свой ключ и не сохранять его на сервер. Но тогда отправитель или сервер должен шифровать каждое сообщение всеми пользовательскими ключами, чтобы его можно было прочесть на любом устройстве. По моему так сделано в iMessage: https://images.apple.com/business/docs/iOS_Security_Guide.pdf , страница 43:
> When a user turns on iMessage on a device, the device generates two pairs of keys for
use with the service: an RSA 1280-bit key for encryption and an ECDSA 256-bit key on
the NIST P-256 curve for signing. The private keys for both key pairs are saved in the
device’s Keychain and the public keys are sent to Apple’s directory service (IDS), where
they are associated with the user’s phone number or email address, along with the
device’s APNs address.
> The user’s outgoing message is individually encrypted for each of the receiver’s
devices.
В случае хранения ключа локально - мы можем очистить историю, уничтожив его и сгенерировав новый ключ. В случае хранения ключа на сервере гарантировать его уничтожение нельзя (мы не можем доверять серверу), разве что сменить пароль, которым зашифрован ключ, при условии что сервер не знает предыдущий пароль.
Мне конечно схема с локалшьным хранением ключа кажется более надежной, но более сложной в реализации.
> Но я не понимаю как хранить ID сообщений - получается что для каждого пользователя оно теперь будет своё. Из этого вытекает, что нельзя будет как-то преобразовывать эти сообщения т.е. редактировать или удалять.
Можно сделать 2 таблицы, одна для хранения id сообщений, другая для хранения зашифрованных копий сообщений для каждого получателя.
> Никак не могу сформулировать структуру при реализации конференций..
Таблица "чаты": chat.id, chat.name, таблица для хранения списка участников (с периодом времени): participant.userId, participant.chatId, participant.since, participant.till. Ну и соответственно таблицы для хранения сообщений, вид которых зависит от выбранной схемы.
Тут правда есть проблема, что на сервере хранится полный список участников чата, который может заинтересовать злоумышленников и агентов правителтьства. Если ее не хранить на сервере в открытую (например, как-то хранить в зашифрованном виде в аккаунте пользователя), может быть было бы лучше.
Что касается твоей схемы, вместо 2 таблиц inbox/outbox можно сделать одну с полем типа сообщения.
> Когда при выводе нового элемента, мы устанавливаем на него обработчик, то мы его не переназначаем, а добавляем новый, и каждый раз когда происходит это событие, обработчик выполняется столько раз, сколько мы выводили элемент
Это проблема в твоем коде, что ты так делаешь. Не надо назначать обработик несколько раз.
Надо либо ставить обработчик только один раз, при создании или обнаружении элемента, либо же (если есть много однотипных элементов) выгоднее ставить не много обработчиков, а один обработчик на родительский элемент и ловить всплывающие снизу дерева DOM события.
Также, ставить обработчик нужно только на принадлежащие данному виджету элементы (если выводится несколько однотипных виджетов).
В твоем примере кода, когда ты вставляешь HTML код из template в DOM, тогда же надо и ставить обработчики, и делать это только один раз. То есть сделать например так:
Widget.prototype.handleShowFormButton = function() {
this.view.button.click(this.showForm.bind(this));
}
Widget.prototype.showForm = function () {
if (!this.view.isFormCreated()) {
this.view.createForm(); // создает форму без проверки, есть она или нет
this.handleFormSubmit(); // ставит на нее обработчики
}
};
Ну или, если бы установкой обработчиков занимался view, то можно было бы гарантировать что они ставятся только один раз при вставке формы в DOM.
> Чтобы это пификсить нужно убрать с элемента обработчик функцией .off()
Выглядит как костыль. Проще просто не ставить обработчик несколько раз.
> У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори.
> Это должно быть сделано с помощью функций JOIN и GROUP:
Я не очень понял, как выравнивание сообщений связано с SQL-запросами?
> трачу ваше время.
А я отвечаю только когда есть свободное время, так что ничего страшного
use описан тут http://php.net/manual/ru/functions.anonymous.php
Он позволяет передать копию значения переменной снаружи внутрь анонимной функции (по умолчанию в функции доступны только созданные внутри нее переменные). Если использовать &$foo вместо $foo, то передается не копия значения, а ссылка на саму переменную, и код внутри функции может менять эту переменную.
>>1028199
Вообще, я не знаю, как "правильно" сделать схему хранения сообщений, потому давай сравним варианты.
Одно мне пока понятно - чаты и диалоги лучше делать одинаковым способом, то есть представить диалог 2 пользователей как чат из 2 участников.
Первый вариант - сделать у каждого пользователя списки входящих и исходящих сообщений (по аналогии с почтовым ящиком), и помещать копии сообщения как отправителю, так и получателю. При этом каждый может независимо управлять своей историей сообщений, например, очищать ее. Для чатов сообщение придется копировать многократно.
При этом, чтобы связать сообщения, можно сделать какой-нибудь добавочный id. Можно например сделать таблицу сообщений (где и будет этот id), и отдельно таблицу, которая хранит копию сообщения для конкретного получателя.
Шифрование проблем никаких не вызывает: отправитель шифрует сообщение открытым ключом пользователя и помещает его в "входящие". В чате отправитель (или сервер) делает N копий, для каждого участника. Новый участник чата не видит старые сообщения.
Другой вариант - сделать сущность "беседа" (чат между 2 или более пользователями) и прикреплять каждое сообщение к "беседе". В этом случае у нас имеется одна копия сообщения. Очистку истории (только с одной стороны) можно реализовать добавлением поля вроде "время, начиная с которого видны сообщения". Это позволяет одному пользователю в диалоге или чате очистить историю на своей стороне, не трогая историю других участников. Также это позволяет новым присоединившимся к чату пользователям не видеть старые сообщения.
Конечно, есть еще вариант отказаться от возможности индивидально чистить историю и сделать так, что любой участник беседы может удалить сообщения в ней.
Для реализации шифрования нам придется сделать ключ "беседы", так, что у всех участников беседы есть приватный ключ для расшифровки сообщения. То есть когда создается новый диалог, участники сообща генерируют приватный ключ, открытый ключ, и шифруют сообщения открытым ключом при отправке в беседу. При этом надо рассмотреть такие сценарии:
- из чата вышел участник - нужен новый ключ для новых сообщений, чтобы он их не мог расшифровать
- в чат добавился участник - нужен новый ключ, чтобы он не видел более старые сообщения
- пользователь потерял пароль/устройство и приватный ключ для расшифровки входящих сообщений - что делать? наверно, генерировать новый ключ
То есть в одной беседе может быть использоваться несколько ключей в разные промежутки времени и пользователь должен хранить их копии, если хочет читать сообщения в ней. И тогда нужна какая-то таблица для хранения информации, какой пользователь за какой промежуток времени видел беседу и какой ключ использовал.
Так как ключей много, компрометация одного из них не дает доступа ко всем сообщениям, а только к сообщениям за один период времени в одной беседе. Но где-то все эти ключи бесед надо хранить - и если мы хотим доступ с нескольких устройств, то ключи придется хранить на сервере (зашифрованные главным ключом).
В общем, есть 2 варианта, предлагаю сравнить их преимущества и недостатки.
Кстати, кроме шифрования сообщений нужно еще предусмотреть подпись - чтобы получатель мог убедиться, что оно отправлено именно отправителем.
Также, вопрос еще, где хранить ключи. Можно иметь единый ключ пользователя, хранящийся на сервере и зашифрованный паролем (устройства скачивает шифрованный ключ и расшифровывает локально). Либо же можно для каждого устройства иметь свой ключ и не сохранять его на сервер. Но тогда отправитель или сервер должен шифровать каждое сообщение всеми пользовательскими ключами, чтобы его можно было прочесть на любом устройстве. По моему так сделано в iMessage: https://images.apple.com/business/docs/iOS_Security_Guide.pdf , страница 43:
> When a user turns on iMessage on a device, the device generates two pairs of keys for
use with the service: an RSA 1280-bit key for encryption and an ECDSA 256-bit key on
the NIST P-256 curve for signing. The private keys for both key pairs are saved in the
device’s Keychain and the public keys are sent to Apple’s directory service (IDS), where
they are associated with the user’s phone number or email address, along with the
device’s APNs address.
> The user’s outgoing message is individually encrypted for each of the receiver’s
devices.
В случае хранения ключа локально - мы можем очистить историю, уничтожив его и сгенерировав новый ключ. В случае хранения ключа на сервере гарантировать его уничтожение нельзя (мы не можем доверять серверу), разве что сменить пароль, которым зашифрован ключ, при условии что сервер не знает предыдущий пароль.
Мне конечно схема с локалшьным хранением ключа кажется более надежной, но более сложной в реализации.
> Но я не понимаю как хранить ID сообщений - получается что для каждого пользователя оно теперь будет своё. Из этого вытекает, что нельзя будет как-то преобразовывать эти сообщения т.е. редактировать или удалять.
Можно сделать 2 таблицы, одна для хранения id сообщений, другая для хранения зашифрованных копий сообщений для каждого получателя.
> Никак не могу сформулировать структуру при реализации конференций..
Таблица "чаты": chat.id, chat.name, таблица для хранения списка участников (с периодом времени): participant.userId, participant.chatId, participant.since, participant.till. Ну и соответственно таблицы для хранения сообщений, вид которых зависит от выбранной схемы.
Тут правда есть проблема, что на сервере хранится полный список участников чата, который может заинтересовать злоумышленников и агентов правителтьства. Если ее не хранить на сервере в открытую (например, как-то хранить в зашифрованном виде в аккаунте пользователя), может быть было бы лучше.
Что касается твоей схемы, вместо 2 таблиц inbox/outbox можно сделать одну с полем типа сообщения.
> Когда при выводе нового элемента, мы устанавливаем на него обработчик, то мы его не переназначаем, а добавляем новый, и каждый раз когда происходит это событие, обработчик выполняется столько раз, сколько мы выводили элемент
Это проблема в твоем коде, что ты так делаешь. Не надо назначать обработик несколько раз.
Надо либо ставить обработчик только один раз, при создании или обнаружении элемента, либо же (если есть много однотипных элементов) выгоднее ставить не много обработчиков, а один обработчик на родительский элемент и ловить всплывающие снизу дерева DOM события.
Также, ставить обработчик нужно только на принадлежащие данному виджету элементы (если выводится несколько однотипных виджетов).
В твоем примере кода, когда ты вставляешь HTML код из template в DOM, тогда же надо и ставить обработчики, и делать это только один раз. То есть сделать например так:
Widget.prototype.handleShowFormButton = function() {
this.view.button.click(this.showForm.bind(this));
}
Widget.prototype.showForm = function () {
if (!this.view.isFormCreated()) {
this.view.createForm(); // создает форму без проверки, есть она или нет
this.handleFormSubmit(); // ставит на нее обработчики
}
};
Ну или, если бы установкой обработчиков занимался view, то можно было бы гарантировать что они ставятся только один раз при вставке формы в DOM.
> Чтобы это пификсить нужно убрать с элемента обработчик функцией .off()
Выглядит как костыль. Проще просто не ставить обработчик несколько раз.
> У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори.
> Это должно быть сделано с помощью функций JOIN и GROUP:
Я не очень понял, как выравнивание сообщений связано с SQL-запросами?
> трачу ваше время.
А я отвечаю только когда есть свободное время, так что ничего страшного
Вообще, мне тут пришла в голову мысль, что с помощью только передачи шифрованных сообщений можно передавать и другие данные так, что сервер не сможет их получить. Ну например, мы хотим хранить информацию о пользователе так, чтобы сервер не мог ее видеть, но ее могли бы видеть контакты пользователя. Для этого можно использовать специальный тип сообщений - один клиент посылает другому шифрованный запрос информации о нем, и в ответ получает в зашифрованном сообщении информацию.
То есть может быть можно поручить серверу только передачу сообщений между клиентами, истории хранение шифрованных сообщений и может быть ведение реестра открытых ключей, а все остальные функции реализовать поверх этой абстракции, чтобы сервер имел доступ к как можно меньшему объему информации.
Но тебе наверно пока лучше разобраться с тем, что есть.
Ну и если есть желание, то почитать информацию о протоколе Tox:
- https://en.wikipedia.org/wiki/Tox_(protocol)
- https://github.com/Tox-Docs/Text/tree/master/src_text
и Signal:
- https://en.wikipedia.org/wiki/Signal_Protocol
- https://whispersystems.org/docs/
Так некуда деваться, в мухосрансках есть только два стула, 1C и сладкий хлебушек. Но 1C это вообще не программирование.
На фрилансе тоже хуй найдешь заказы на Java ну или desktop разработку.
Спасибо за ответ.
Как сделать так, чтобы значения чекбоксов на которых нажмет пользователь переходил в мою sql таблицу.
Гуглил но как то ничего не поняля тупой
> главная проблема не выводится значение массива
В документации array_rand написано "returns the key (or keys) of the random entries.", то есть функция возвращает ключ (индекс элемента), а не значение: http://php.net/manual/en/function.array-rand.php
Тебе нужно обратиться к элементу массива под этим новым случайным индексом, тогда получишь значение.
спасибо гуру
Теперь понятно.
Без use — undefined
use ($variable) — только внутрь
use (&$variable) — внутрь и наружу
Единственный вопрос остался: зачем это нужно вообще, если есть аргументы??
При чём здесь жаба? Тут пхп-тред.
Решил проблему, сославшись в функции на глобальную переменную самого замыкания. А как это сделать нормально?
>Мне лень в каждый объект ручками все добавлять, когда все эти значения и так есть в классе.
Убери параметры из конструктора( или сам конструктор, судя по описанию, он тебе только мешает), он просто будет выполнять код при создании объекта.
по типу
кто-то пытается зайти на
site.com/analplugs
его редиректит на главную
site.com
а site.com/analplugs записывается в бд
редирект понятно через какой-нибудь htaccess можно сделать, но как это совместить с записью в бд?
Сервак и без тебя ведет логи запросов ко всем ресурсам, в том числе и несуществующим.
И может кто, предложить решение этой задачи?
https://pastebin.com/Mmiz1HDU
Я смог наваять только такое:
https://pastebin.com/bwMZHvkg
Понимаю что криво, но куда копать не пойму.
Может, подскажите чего?
хочу именно через бд
Да, похоже, оно. Благодарю.
>В общем, есть 2 варианта, предлагаю сравнить их преимущества и недостатки.
Остановимся на первом варианте, т.к. во втором переусложнена генерация ключей. Может быть и нет, сначала мне нужно разобраться с шифрованием
>> Но я не понимаю как хранить ID сообщений - получается что для каждого пользователя оно теперь будет своё. Из этого вытекает, что нельзя будет как-то преобразовывать эти сообщения т.е. редактировать или удалять.
>Можно сделать 2 таблицы, одна для хранения id сообщений, другая для хранения зашифрованных копий сообщений для каждого получателя.
>При этом, чтобы связать сообщения, можно сделать какой-нибудь добавочный id. Можно например сделать таблицу сообщений (где и будет этот id), и отдельно таблицу, которая хранит копию сообщения для конкретного получателя.
Действительно, можно создать таблицу специально чтобы только хранить id, а ящики Inbox и Outbox будут хранить ещё и всё остальное (автора, контент, дату и т.д.).
>Тут правда есть проблема, что на сервере хранится полный список участников чата, который может заинтересовать злоумышленников и агентов правителтьства. Если ее не хранить на сервере в открытую (например, как-то хранить в зашифрованном виде в аккаунте пользователя), может быть было бы лучше.
Да, я тоже размышлял об этом. Мне нужно ещё подумать как тут лучше поступить.
Шифрование
Никак не могу понять как это сделать. Я уже немного знаком с ним, но почему-то даже не могу придумать функцию которая будет шифровать сообщения.
Знаю как сгенерировать ключ с помощь протокола Диффи - Хеллмана, имею небольшое представление о открытых и закрытых ключах, но как с помощью них (ключей) зашифровать сообщение - не представляю.
>Также, вопрос еще, где хранить ключи. Можно иметь единый ключ пользователя, хранящийся на сервере и зашифрованный паролем (устройства скачивает шифрованный ключ и расшифровывает локально).
>устройства скачивает шифрованный ключ и расшифровывает локально
Меня сначала смутило что без js тогда не будет работать приложение, но потом я подумал что можно будет при залогинивании выдавать кукис с расшифрованным ключем.
>Мне конечно схема с локалшьным хранением ключа кажется более надежной, но более сложной в реализации.
Значит нужно оставить это на дальнейшую реализацию.
>> Когда при выводе нового элемента, мы устанавливаем на него обработчик, то мы его не переназначаем, а добавляем новый, и каждый раз когда происходит это событие, обработчик выполняется столько раз, сколько мы выводили элемент
>Это проблема в твоем коде, что ты так делаешь. Не надо назначать обработик несколько раз.
>Надо либо ставить обработчик только один раз, при создании или обнаружении элемента
У меня элемент постоянно обновляется и постоянно нужно ставить новый обработчик.
>либо же (если есть много однотипных элементов) выгоднее ставить не много обработчиков, а один обработчик на родительский элемент и ловить всплывающие снизу дерева DOM события.
Вот так https://jsfiddle.net/jsqt57hz/2/ ?
>В твоем примере кода, когда ты вставляешь HTML код из template в DOM, тогда же надо и ставить обработчики, и делать это только один раз.
А я приводил в пример такой вариант, вы сказали что у виджета может быть свой обработчик событий:
https://arhivach.org/thread/266631/#1018809
>> А что если элемент появляется не сразу? Логично будет задать тогда при его выводе элемента (то есть обработчик будет частью отображения) или в контроллере?
>Во-первых, "установка обработчика" не обязательно значит "установка обработчика на DOM элемент". В виджете может быть своя система событий, и ставится обработчик на внутреннее событие виджета, а не на DOM элемент.
> У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори.
> Это должно быть сделано с помощью функций JOIN и GROUP:
Я не очень понял, как выравнивание сообщений связано с SQL-запросами?
Не выравнивание, а опускание скролла сообщений до последнего сообщения, если я правильно понял терминологию.
Мы с помощью SQL-запросов получаем контакты и последние сообщения, и в ссылку контакта вставляем якорь на id последнего сообщения:
><a class="contact" ... href="conversation.php? ... #message-ID">someUser</a>
><div id="message-ID ... class="message">
Заодно можно сделать и сортировку контактов по последним полученным сообщениям.
>В общем, есть 2 варианта, предлагаю сравнить их преимущества и недостатки.
Остановимся на первом варианте, т.к. во втором переусложнена генерация ключей. Может быть и нет, сначала мне нужно разобраться с шифрованием
>> Но я не понимаю как хранить ID сообщений - получается что для каждого пользователя оно теперь будет своё. Из этого вытекает, что нельзя будет как-то преобразовывать эти сообщения т.е. редактировать или удалять.
>Можно сделать 2 таблицы, одна для хранения id сообщений, другая для хранения зашифрованных копий сообщений для каждого получателя.
>При этом, чтобы связать сообщения, можно сделать какой-нибудь добавочный id. Можно например сделать таблицу сообщений (где и будет этот id), и отдельно таблицу, которая хранит копию сообщения для конкретного получателя.
Действительно, можно создать таблицу специально чтобы только хранить id, а ящики Inbox и Outbox будут хранить ещё и всё остальное (автора, контент, дату и т.д.).
>Тут правда есть проблема, что на сервере хранится полный список участников чата, который может заинтересовать злоумышленников и агентов правителтьства. Если ее не хранить на сервере в открытую (например, как-то хранить в зашифрованном виде в аккаунте пользователя), может быть было бы лучше.
Да, я тоже размышлял об этом. Мне нужно ещё подумать как тут лучше поступить.
Шифрование
Никак не могу понять как это сделать. Я уже немного знаком с ним, но почему-то даже не могу придумать функцию которая будет шифровать сообщения.
Знаю как сгенерировать ключ с помощь протокола Диффи - Хеллмана, имею небольшое представление о открытых и закрытых ключах, но как с помощью них (ключей) зашифровать сообщение - не представляю.
>Также, вопрос еще, где хранить ключи. Можно иметь единый ключ пользователя, хранящийся на сервере и зашифрованный паролем (устройства скачивает шифрованный ключ и расшифровывает локально).
>устройства скачивает шифрованный ключ и расшифровывает локально
Меня сначала смутило что без js тогда не будет работать приложение, но потом я подумал что можно будет при залогинивании выдавать кукис с расшифрованным ключем.
>Мне конечно схема с локалшьным хранением ключа кажется более надежной, но более сложной в реализации.
Значит нужно оставить это на дальнейшую реализацию.
>> Когда при выводе нового элемента, мы устанавливаем на него обработчик, то мы его не переназначаем, а добавляем новый, и каждый раз когда происходит это событие, обработчик выполняется столько раз, сколько мы выводили элемент
>Это проблема в твоем коде, что ты так делаешь. Не надо назначать обработик несколько раз.
>Надо либо ставить обработчик только один раз, при создании или обнаружении элемента
У меня элемент постоянно обновляется и постоянно нужно ставить новый обработчик.
>либо же (если есть много однотипных элементов) выгоднее ставить не много обработчиков, а один обработчик на родительский элемент и ловить всплывающие снизу дерева DOM события.
Вот так https://jsfiddle.net/jsqt57hz/2/ ?
>В твоем примере кода, когда ты вставляешь HTML код из template в DOM, тогда же надо и ставить обработчики, и делать это только один раз.
А я приводил в пример такой вариант, вы сказали что у виджета может быть свой обработчик событий:
https://arhivach.org/thread/266631/#1018809
>> А что если элемент появляется не сразу? Логично будет задать тогда при его выводе элемента (то есть обработчик будет частью отображения) или в контроллере?
>Во-первых, "установка обработчика" не обязательно значит "установка обработчика на DOM элемент". В виджете может быть своя система событий, и ставится обработчик на внутреннее событие виджета, а не на DOM элемент.
> У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори.
> Это должно быть сделано с помощью функций JOIN и GROUP:
Я не очень понял, как выравнивание сообщений связано с SQL-запросами?
Не выравнивание, а опускание скролла сообщений до последнего сообщения, если я правильно понял терминологию.
Мы с помощью SQL-запросов получаем контакты и последние сообщения, и в ссылку контакта вставляем якорь на id последнего сообщения:
><a class="contact" ... href="conversation.php? ... #message-ID">someUser</a>
><div id="message-ID ... class="message">
Заодно можно сделать и сортировку контактов по последним полученным сообщениям.
Как дебажить Request/Response между React+Redux и Silex?
Я пытаюсь отправить POST запрос с помощью метода Fetch() на api своего приложения.
В хроме я вижу что запрос отправлен, и содержит некоторые данные, которые я отправляю.
Но, не могу получить эти данные в контроллере из Request с помощью all() и записать их в лог,
Monolog пишет пустую строку (или ноль).
Данные перед отправкой обрабатываю JSON.stringify(data) https://github.com/enotocode/birthday_reminder/blob/master/src/client/Login/actions.js#L49
на сервере массив из реквеста превращаю в строку implode() и пишу info(printf(data)) https://github.com/enotocode/birthday_reminder/blob/master/src/server/Controllers/SignupController.php#L23
Лог https://github.com/enotocode/birthday_reminder/blob/master/src/server/public/development.log#L51
Почему не получается вытянуть из реквеста данные? В чем может быть проблема?
Смотреть надо в инструментах разработчика - на тип запроса, на Content-Type и тело запроса (можно нажать view source рядом с request payload).
PHP при поступлении POST-запроса разбирает тело запроса и помещает параметры в переменную $_POST, откуда их берет Request.
Но PHP разбирает не любые данные, а только данные в 2 форматах (которые использует браузер для форм):
http://php.net/manual/ru/reserved.variables.post.php
> Ассоциативный массив данных, переданных скрипту через HTTP метод POST в случае использования в запросе в качестве HTTP Content-Type application/x-www-form-urlencoded или multipart/form-data .
Ты передаешь данные в каком-то своем придуманном формате и естественно что PHP их игнорирует. Причем формат у тебя странный - данные передаешь как JSON но с типом plain/text.
Проще всего не использовать JSON, а использовать один из стандартных способов кодирования. Либо использовать JSON и в PHP самому разбирать тело запроса.
Также, по коду я бы советовал вынести работу с API в отдельный слой, а не мешать все в кучу в actions.
Также, завис на этом коде, пока не понял, что тут 2 функции:
> .then(
> response => response.json(),
> error => console.log('An error occured.', error)
> )
Ну и синтаксис они придумали в новом JS, нечитаемый абсолютно.
Также, по моему у тебя ошибка в обработчике ошибок. error => console.log('An error occured.', error) возвращает null и это значит что дальше выполнится блок then с этим null ( json => dispatch(recieveInputs(json)) ). То есть ты как бы "обработал" ошибку и превратил ее в успешный результат. Если ты не выбросил исключение то это значит что ошибка полностью обработана.
Пожалуйста, изучи внимательно, как надо работать с ошибками в промисах. Там конечно это все очень неудачно на мой взгляд сделано, тем не менее, надо в этом хорошо разбираться.
Чтобы проверить, что ты разбираешься, вот тебе вопрос.
Что если сервер вернет неправильный JSON? В этом случае response => response.json выкинет исключение, then() его перехватит и что будет дальше? Выведется ли сообщение об ошибке или будет потеряно?
Смотреть надо в инструментах разработчика - на тип запроса, на Content-Type и тело запроса (можно нажать view source рядом с request payload).
PHP при поступлении POST-запроса разбирает тело запроса и помещает параметры в переменную $_POST, откуда их берет Request.
Но PHP разбирает не любые данные, а только данные в 2 форматах (которые использует браузер для форм):
http://php.net/manual/ru/reserved.variables.post.php
> Ассоциативный массив данных, переданных скрипту через HTTP метод POST в случае использования в запросе в качестве HTTP Content-Type application/x-www-form-urlencoded или multipart/form-data .
Ты передаешь данные в каком-то своем придуманном формате и естественно что PHP их игнорирует. Причем формат у тебя странный - данные передаешь как JSON но с типом plain/text.
Проще всего не использовать JSON, а использовать один из стандартных способов кодирования. Либо использовать JSON и в PHP самому разбирать тело запроса.
Также, по коду я бы советовал вынести работу с API в отдельный слой, а не мешать все в кучу в actions.
Также, завис на этом коде, пока не понял, что тут 2 функции:
> .then(
> response => response.json(),
> error => console.log('An error occured.', error)
> )
Ну и синтаксис они придумали в новом JS, нечитаемый абсолютно.
Также, по моему у тебя ошибка в обработчике ошибок. error => console.log('An error occured.', error) возвращает null и это значит что дальше выполнится блок then с этим null ( json => dispatch(recieveInputs(json)) ). То есть ты как бы "обработал" ошибку и превратил ее в успешный результат. Если ты не выбросил исключение то это значит что ошибка полностью обработана.
Пожалуйста, изучи внимательно, как надо работать с ошибками в промисах. Там конечно это все очень неудачно на мой взгляд сделано, тем не менее, надо в этом хорошо разбираться.
Чтобы проверить, что ты разбираешься, вот тебе вопрос.
Что если сервер вернет неправильный JSON? В этом случае response => response.json выкинет исключение, then() его перехватит и что будет дальше? Выведется ли сообщение об ошибке или будет потеряно?
>Но PHP разбирает не любые данные, а только данные в 2 форматах (которые использует браузер для форм)
Значит переменные $_POST и $_GET будут всегда пусты, если передавать данные в JSON формате? Существуют еще удобные способы проверять данные, которые получил PHP в теле запроса POST?
>Причем формат у тебя странный - данные передаешь как JSON но с типом plain/text.
Исправил, добавив заголовок ('Content-type', 'application/json; charset=utf-8');
>Проще всего не использовать JSON, а использовать один из стандартных способов кодирования.
Почему так проще? Для urlenencoded и form-data нужно специально кодировать данные менее удобным способом, чем JSON.stringify(). Или ты имеешь ввиду если передавать их из формы?
>Также, по коду я бы советовал вынести работу с API в отдельный слой, а не мешать все в кучу в actions.
>Также, по моему у тебя ошибка в обработчике ошибок.
Это условный код из мануала Redux, я еще не смотрел как сделаны реальные приложения. Но написано, что тут в конце цепочки не следует добавлять блок catch во избежание цикла с ошибкой 'Unexpected batch number' если рендеришь результат. Каменистое дно.
>Что если сервер вернет неправильный JSON? В этом случае response => response.json выкинет исключение, then() его перехватит и что будет дальше? Выведется ли сообщение об ошибке или будет потеряно?
Браузер вероятно выведет ошибку в консоли, и наверное она попадет в качестве аргумента в recieveInputs(json)
charset добавляется только для содержимого с типом text/*. В JSON кодировка определена стандартом и указывать ее не надо.
сохранение через сингелтон очевидно ,
> некоторых упражнений способ сохранения может измениться и нужно, чтобы это можно было сделать легко.
тут я думаю нужно делать как то через фабрику
ну и точно нужно делить расчёт балов в модель\AR
нужно писать хендлер , и когда реквест будет на не существ страницу , ловить это и записывать в бд после делать редирект на главную
если они уже есть в классе то в методе класса ты можешь ими оперировать через $this->foo , очевидно если это не статический метод
это js , синтаксис на c похож у многих языков , так как они почти все дети с языка
запихнуть их очевидно в форму и делать сабмит
https://stackoverflow.com/questions/2309801/how-to-submit-checkbox-values-with-php-post-method
>Значит переменные $_POST и $_GET будут всегда пусты, если передавать данные в JSON формате? Существуют еще удобные способы проверять данные, которые получил PHP в теле запроса POST?
>
пост будет пуст да , способы есть https://stackoverflow.com/questions/40108736/php-get-json-post-data
пиздец. Просто пиздец всё оказалось настолько просто. Спасибо тебе огромнейшее я столько думал над этим.
Все же от тебя зависит. От того как ты усваиваешь информацию и от того, сколько времени ты будешь уделять своему обучению.
Всё в твоих руках.
Маловероятно. Если бы все было так просто, все бы давно уже устроились работать программистами. Так как в РФ средняя зарплата за апр. 2017 - 38906 руб, а медианная (50% людей получают меньше этой цифры) - около 30 000 р
Лучше поспрашивать у анонов, которые уже прошли обучение и устроились на работу. Например, в работа-треде который тут где-то есть.
Ну так то да.
>>1029339
>>Что если сервер вернет неправильный JSON? В этом случае response => response.json выкинет исключение, then() его перехватит и что будет дальше? Выведется ли сообщение об ошибке или будет потеряно?
>Браузер вероятно выведет ошибку в консоли, и наверное она попадет в качестве аргумента в recieveInputs(json)
Прочитал про промисы статью кантора внимательнее, и провел эксперимент, если метод response.json() выкинет ошибку, то она не будет отображаться в консоли пишет кантор (но Chrome ее выводит), и поскольку следующий блок then() не имеет функции rejected, чтобы его вызвать, и в конце цепочки нет catch, то можно считать, шибка будет потеряна.
>charset добавляется только для содержимого с типом text/*. В JSON кодировка определена стандартом и указывать ее не надо.
Лол, пример взял из учебника Кантора. Проверил сам, действительно в стандарте написано что JSON text SHALL be encoded in UTF-8, UTF-16, or UTF-32, и UTF-8 по дефолту. Но разве это не подходит под случай "явное лучше не явного"?
Почему ты так считаешь?
>средняя зарплата за апр. 2017 - 38906 руб
Чиво, блядь? Я про ДС, есличо. Тут стажёр эти ёбаные 40к будет получать уже в первый месяц работы.
Два чая, ток тут не про обучение будет верно, а вообще про все. Если сильно захочет то будет и 200к получать, конечно если хватит ума, а так если он обычный таракан который решил, что это легко и на этом можно навариться, то правильно его тралят.
file:///C:/Users/microwavenovka/Desktop/HTML5/Learning/Learn1.html
>конечно если хватит ума
Помимо ума ещё нужны soft skills. За 200к их от тебя будут требовать, ибо выполняемые тобой функции будут выходить за рамки тупого кодинга.
круто))))0000
>Что касается твоей схемы, вместо 2 таблиц inbox/outbox можно сделать одну с полем типа сообщения.
А можно вообще не указывать этот тип. Зачем это может пригодиться?
можешь начать с 5.6 базовые знания применимы и для 7 , но на 5.6 ещё много легаси кода что == работе
Всё, что написано на 5.6, будет работать на 7.
>сохранение через сингелтон очевидно
Я подумал, что подразумевается, что будет использоваться фрейворк и такое можно опустить.
>через фабрику
Зачем фабрику, почему не декоратор?
>ну и точно нужно делить расчёт балов в модель\AR
Это вообще не понял.
Да, это (на мой взгляд) проблема промисов - в отличие от обычного синхронного кода, где ошибки по умолчанию вылетают наружу, промисы по умолчанию их проглатывают и ты явно должен делать что-то, чтобы их обработать.
Потому в спецификации добавили "костыль" (на мой взгляд костыль) - они сделали вывод необработанных ошибок в консоль на следующем шаге цикла событий и сделали событие, по моему unhandledrejection, чтобы ловить такие ошибки программно. Потому ты видишь сообщение в консоли.
>декоратор
так как декоратор расширяет класс , а фабрика описывает действие которое может быть реализовано в разных типах вопросов по разному
Потому что тело твоего цикла не выполняется ни разу. Уже в самом начале условие продолжения цикла $credit <= 5000 ложно.
1. Настроить сервер и C:\Windows\System32\drivers\etc\hosts
2. Использовать протухший денвер
3. Перестать насиловать мозг бессмысленной херней и использзваь php -S 127.0.0.1:8888
Ебать, я такое в жизни не осилю
Учи матчасть. Браузер узнает ip адрес сайта c благодаря dns или файлу hosts. Денвер перезаписывал на лету hosts в соответствии с именем папки. Но это все мхом поросло, c тех пор как в php встроили сервер и все современные фреймворки умеют запускать сайт в режиме разработки через него. Это обязательная часть скафолдинга. Ты сам можешь сам запускать php -S ip:port из папки с сайтом. Открой папку в проводнике и введи адресной строке cmd, нажми enter. Появится консоль. Введи в нее php -S 127.0.0.1:8080, жми enter.
Открой в браузере адрес 127.0.0.1:8080 или пропиши в hosts:
название_сайта 127.0.0.1.
Тогда можешь открывать сайт по имени. Главное необходимо прописать путь к php в переменную среды Path, как на пике.
лол править hots , говорить что всё мхом поросло
не проше использовать тот же OpenServer который делает это всё автоматом при запуске
Нахуя вооще что-то править, превращать десктоп в сервер. Запускай laravel через artisan, попивая смузи.
Если надо больше - используй VM и готовые аплиансы или vargant https://app.vagrantup.com/boxes/search
vagrant
можно то и doker но проблема в том что зачем мне пердолиться с всей этой штукой день , если я могу поставить опен сервер и запустить вс в 2 клика ?
А зачем тогда сервер? Достаточно только php, ну и composer. В php есть сервер для разработки, есть sqlite
Опечаточник - https://ideone.com/eumFsz
Yoda Speak - https://3v4l.org/46mlk
Пиши верно - https://3v4l.org/OU9Ru
Сумма прописью - https://3v4l.org/GLjK8
Я у мамы калькулятор - https://3v4l.org/3O7ng
редисы , постгресы и тд
Про фигурные скобки - тут http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
> кубы http://ideone.com/LitWO1
exit не нужен, так как в случае даблов другие условия уже проверяться не будут. А в остальном, верно.
> айфон http://ideone.com/lHOqEL
Ок, тоже верно.
>>1029861
В случае с Апачем это делается так. Придумать домен, вписать его в hosts (чтобы браузер мог преобразовать домен в IP адрес), затем добавить VirtualHost в конфиг Апача, чтобы он знал, в какой папке лежит этот сайт. Но в слусае WAMP может это как-то по-другому делается, ты документацию смотреть не пробовал?
>>1029807
Любую, можно 7, только выучи отличия между этими версиями.
>>1029721
Не знаю, если ты можешь без этого обойтись, то можно и не делать.
>>1029617
Ты дал ссылку на файл на своем компьютере.
Про фигурные скобки - тут http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
> кубы http://ideone.com/LitWO1
exit не нужен, так как в случае даблов другие условия уже проверяться не будут. А в остальном, верно.
> айфон http://ideone.com/lHOqEL
Ок, тоже верно.
>>1029861
В случае с Апачем это делается так. Придумать домен, вписать его в hosts (чтобы браузер мог преобразовать домен в IP адрес), затем добавить VirtualHost в конфиг Апача, чтобы он знал, в какой папке лежит этот сайт. Но в слусае WAMP может это как-то по-другому делается, ты документацию смотреть не пробовал?
>>1029807
Любую, можно 7, только выучи отличия между этими версиями.
>>1029721
Не знаю, если ты можешь без этого обойтись, то можно и не делать.
>>1029617
Ты дал ссылку на файл на своем компьютере.
Сильно захотеть недостаточно.
>>1029613
Это в общем по стране, а не среди сотрудников определенной специальности в отдельном городе.
>>1029583
Я посмотрел RFC, который определяет тип application/json: https://tools.ietf.org/html/rfc4627
Там написано:
> The MIME media type for JSON text is application/json.
> Required parameters: n/a
> Optional parameters: n/a
charset - это именно parameter и тут он не определен.
Также, там написано, что кодировка определяется по кодированию первых 2 символов в JSON-данных.
Также, для надежности, я глянул еще RFC по MIME-типам: https://tools.ietf.org/html/rfc2046#section-4.1.2
> Charset Parameter
> A critical parameter that may be specified in the Content-Type field
> for "text/plain" data is the character set
> ....
> The specification for any future subtypes of "text" must specify
> whether or not they will also utilize a "charset" parameter, and may
> possibly restrict its values as well.
> ...
> Other media types than subtypes of "text" might choose to employ the
> charset parameter as defined here, but with the CRLF/line break
> restriction removed.
> ....
> The "charset" parameter has been defined primarily for the purpose of
> textual data, and is described in this section for that reason.
> However, it is conceivable that non-textual data might also wish to
> specify a charset value for some purpose, in which case the same
> syntax and values should be used.
То есть этот параметр определен для тестовых данных. Хотя там написано что он может использоваться и для других типов данных, в описании application/json мы такого не видим. И конечно, браузеры могут его интерпретировать или игнорировать, но стандартом поведение никак не определено.
Сильно захотеть недостаточно.
>>1029613
Это в общем по стране, а не среди сотрудников определенной специальности в отдельном городе.
>>1029583
Я посмотрел RFC, который определяет тип application/json: https://tools.ietf.org/html/rfc4627
Там написано:
> The MIME media type for JSON text is application/json.
> Required parameters: n/a
> Optional parameters: n/a
charset - это именно parameter и тут он не определен.
Также, там написано, что кодировка определяется по кодированию первых 2 символов в JSON-данных.
Также, для надежности, я глянул еще RFC по MIME-типам: https://tools.ietf.org/html/rfc2046#section-4.1.2
> Charset Parameter
> A critical parameter that may be specified in the Content-Type field
> for "text/plain" data is the character set
> ....
> The specification for any future subtypes of "text" must specify
> whether or not they will also utilize a "charset" parameter, and may
> possibly restrict its values as well.
> ...
> Other media types than subtypes of "text" might choose to employ the
> charset parameter as defined here, but with the CRLF/line break
> restriction removed.
> ....
> The "charset" parameter has been defined primarily for the purpose of
> textual data, and is described in this section for that reason.
> However, it is conceivable that non-textual data might also wish to
> specify a charset value for some purpose, in which case the same
> syntax and values should be used.
То есть этот параметр определен для тестовых данных. Хотя там написано что он может использоваться и для других типов данных, в описании application/json мы такого не видим. И конечно, браузеры могут его интерпретировать или игнорировать, но стандартом поведение никак не определено.
> и поскольку следующий блок then() не имеет функции rejected, чтобы его вызвать
Вот тут неточность. Ошибка теряется не поэтому.
Если ты не передаешь функцию onRejected в then, то вместо нее будет подставлена функция function Thrower(e) { throw e; }. Это не вызывает потерю ошибки.
Ошибка в твоем коде в том, что функция-обработчик ошибки error => console.log(error) не выкидывает исключение, а возвращает null и это значит, что ошибка обработана и новый промис резолвится в это значение, и этот null передается дальше по цепочке then.
То есть, разберем такой пример:
var p = new Promise(function (resolve, reject) {
reject(new Error);
});
var p2 = p.then(function () {}, function (e) {
console.log(e);
return null; // ошибка, должно быть throw
});
p2.then(....);
В данном примере - p будет rejected, но p2 будет resolved в значение null, так как мы обработали ошибку в then и вернули новое значение. Чтобы p2 также была rejected, мы должны вместо return null поставить throw e; то есть перевыбросить исключение.
То есть функция-обработчик (onFullfilled, onRejected) может либо выбросить исключение - в этом случае p2 будет rejected, либо что-то вернуть - в этом случае p2 ресолвится в это значение.
Ты не перевыбрасвыаешь исключение в onRejected, и это воспринимается, как будто бы ты обработал и исправил ошибку и вернул новое значение, и следующие then в цепочке будут работать с этим значением, как будто бы ошибки и не было.
Вообще, может быть, тебе стоит разобрать пример реализации промисов вот тут: https://www.promisejs.org/implementing/ ?
----
И еще. Это конечно мое мнение, но стрелочные функции смотрятся хорошо не везде. Они были придуманы для сокращения записи простых функций-выражений вроде такого случая:
var result = array.filter(function (x) { return x > 0; });
var result = array.filter(x => x > 0);
В этом примере код со стрелочной функцией короче и читабельнее.
Но в твоем примере, error => console.log(error) - я не уверен, что использование стрелочной функции тут улучшает читабельность кода. Хотя бы потому, что в твоем коде подразумевается { return console.log(error); } и я не понимаю, зачем тут return.
Некоторые думают, что слово function - это устаревший подход, а стрелочные функции - новый, но мне кажется что это просто результат заблуждения и непонимания цели, для которой новый синтаксис был введен.
К сожалению, и в официальных мануалах этого не понимают. Вот пример из документации MDN ( https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions ):
> // Destructuring within the parameter list is also supported
> var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
Это какой-то антипример, как писать ни в коем случае не надо, так как я это даже прочесть не могу. Что это вообще такое?
К тому же они умудрились создать конфликт в синтаксисе стрелочных функций с синтаксисом литералов-объектов:
> var func = () => { foo: 1 };
> // Вызов func() возвращает undefined!
Впрочем, для тех, кто с веб-технологиями и JS знаком не первый день, ничего нового. Они всегда разрабатывались так же бестолково.
> и поскольку следующий блок then() не имеет функции rejected, чтобы его вызвать
Вот тут неточность. Ошибка теряется не поэтому.
Если ты не передаешь функцию onRejected в then, то вместо нее будет подставлена функция function Thrower(e) { throw e; }. Это не вызывает потерю ошибки.
Ошибка в твоем коде в том, что функция-обработчик ошибки error => console.log(error) не выкидывает исключение, а возвращает null и это значит, что ошибка обработана и новый промис резолвится в это значение, и этот null передается дальше по цепочке then.
То есть, разберем такой пример:
var p = new Promise(function (resolve, reject) {
reject(new Error);
});
var p2 = p.then(function () {}, function (e) {
console.log(e);
return null; // ошибка, должно быть throw
});
p2.then(....);
В данном примере - p будет rejected, но p2 будет resolved в значение null, так как мы обработали ошибку в then и вернули новое значение. Чтобы p2 также была rejected, мы должны вместо return null поставить throw e; то есть перевыбросить исключение.
То есть функция-обработчик (onFullfilled, onRejected) может либо выбросить исключение - в этом случае p2 будет rejected, либо что-то вернуть - в этом случае p2 ресолвится в это значение.
Ты не перевыбрасвыаешь исключение в onRejected, и это воспринимается, как будто бы ты обработал и исправил ошибку и вернул новое значение, и следующие then в цепочке будут работать с этим значением, как будто бы ошибки и не было.
Вообще, может быть, тебе стоит разобрать пример реализации промисов вот тут: https://www.promisejs.org/implementing/ ?
----
И еще. Это конечно мое мнение, но стрелочные функции смотрятся хорошо не везде. Они были придуманы для сокращения записи простых функций-выражений вроде такого случая:
var result = array.filter(function (x) { return x > 0; });
var result = array.filter(x => x > 0);
В этом примере код со стрелочной функцией короче и читабельнее.
Но в твоем примере, error => console.log(error) - я не уверен, что использование стрелочной функции тут улучшает читабельность кода. Хотя бы потому, что в твоем коде подразумевается { return console.log(error); } и я не понимаю, зачем тут return.
Некоторые думают, что слово function - это устаревший подход, а стрелочные функции - новый, но мне кажется что это просто результат заблуждения и непонимания цели, для которой новый синтаксис был введен.
К сожалению, и в официальных мануалах этого не понимают. Вот пример из документации MDN ( https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Functions/Arrow_functions ):
> // Destructuring within the parameter list is also supported
> var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
Это какой-то антипример, как писать ни в коем случае не надо, так как я это даже прочесть не могу. Что это вообще такое?
К тому же они умудрились создать конфликт в синтаксисе стрелочных функций с синтаксисом литералов-объектов:
> var func = () => { foo: 1 };
> // Вызов func() возвращает undefined!
Впрочем, для тех, кто с веб-технологиями и JS знаком не первый день, ничего нового. Они всегда разрабатывались так же бестолково.
> Существуют еще удобные способы проверять данные, которые получил PHP в теле запроса POST?
Ты можешь прочитать тело POST и распарсить его самостоятельно или используя какую-нибудь библиотеку (а можешь даже написать и опубликовать свою): http://php.net/manual/ru/wrappers.php.php#wrappers.php.input
> Для urlenencoded и form-data нужно специально кодировать данные менее удобным способом, чем JSON.stringify().
Некоторые библиотеки (jQuery) умеют кодировать их автоматически, также доступен объект FormData, который умеет их кодировать. Наверно, кодировать на стороне клиента их было бы проще, чем впиливать поддержку на стороне PHP, но я в общем-то ничего против передачи JSON не имею - стандартам это никак не противоречит при указании корректных Content-Type/Content-Length
> Но написано, что тут в конце цепочки не следует добавлять блок catch во избежание цикла с ошибкой 'Unexpected batch number' если рендеришь результат.
Лучше бы разобраться, что это значит, так как я, например, вообще ничего не понял и первый раз слышу про эту ошибку.
В любом случае, ошибки нужно обрабатывать. Ты не должен полагаться на то, что сервер будет доступен в 100% случаев и всегда выдавать корректные ответы. Вот мой урок про аякс, перечитай его, если еще не читал, там упоминаются ошибки: https://github.com/codedokode/pasta/blob/master/js/ajax.md
Редукс или не редукс, это значения не имеет, ошибки надо обрабатывать.
Также, еще хорошо бы конечно разделять ошибки на нормальные (не удалось связаться с сервером) и ошибки в программе (обращение к несуществующей переменной, деление на ноль и другие исключения). И при ошибке связи с сервером мы предлагаем пользователю попробовать еще раз, а при вызове несуществующей функции мы констатируем, что приложение безнадежно сломано, логгируем это на сервер и предлагаем перезагрузить страницу.
>>1029324
Для дампа данных лучше использовать не implode, а print_r(..., true) или var_export или (внезапно) json_encode. Я обычно просто ставлю var_dump(); die() и смотрю в отладчике ответ.
Кстати, в отладчике Хрома в Network есть несколько полезных функций, вызываемых через правую кнопку. Это replay request и возможность скопировать командную строку для curl для отправки такого же запроса со всеми заголовками из консоли.
> Существуют еще удобные способы проверять данные, которые получил PHP в теле запроса POST?
Ты можешь прочитать тело POST и распарсить его самостоятельно или используя какую-нибудь библиотеку (а можешь даже написать и опубликовать свою): http://php.net/manual/ru/wrappers.php.php#wrappers.php.input
> Для urlenencoded и form-data нужно специально кодировать данные менее удобным способом, чем JSON.stringify().
Некоторые библиотеки (jQuery) умеют кодировать их автоматически, также доступен объект FormData, который умеет их кодировать. Наверно, кодировать на стороне клиента их было бы проще, чем впиливать поддержку на стороне PHP, но я в общем-то ничего против передачи JSON не имею - стандартам это никак не противоречит при указании корректных Content-Type/Content-Length
> Но написано, что тут в конце цепочки не следует добавлять блок catch во избежание цикла с ошибкой 'Unexpected batch number' если рендеришь результат.
Лучше бы разобраться, что это значит, так как я, например, вообще ничего не понял и первый раз слышу про эту ошибку.
В любом случае, ошибки нужно обрабатывать. Ты не должен полагаться на то, что сервер будет доступен в 100% случаев и всегда выдавать корректные ответы. Вот мой урок про аякс, перечитай его, если еще не читал, там упоминаются ошибки: https://github.com/codedokode/pasta/blob/master/js/ajax.md
Редукс или не редукс, это значения не имеет, ошибки надо обрабатывать.
Также, еще хорошо бы конечно разделять ошибки на нормальные (не удалось связаться с сервером) и ошибки в программе (обращение к несуществующей переменной, деление на ноль и другие исключения). И при ошибке связи с сервером мы предлагаем пользователю попробовать еще раз, а при вызове несуществующей функции мы констатируем, что приложение безнадежно сломано, логгируем это на сервер и предлагаем перезагрузить страницу.
>>1029324
Для дампа данных лучше использовать не implode, а print_r(..., true) или var_export или (внезапно) json_encode. Я обычно просто ставлю var_dump(); die() и смотрю в отладчике ответ.
Кстати, в отладчике Хрома в Network есть несколько полезных функций, вызываемых через правую кнопку. Это replay request и возможность скопировать командную строку для curl для отправки такого же запроса со всеми заголовками из консоли.
Я еще хочу предупредить, что если на сервере хранить в открытую свойства сообщений (кто, кому, когда что отправил), это опять же снижает защищенность и повышает риск утечки данных. Ну и правительства тоже заинтересованы в получении такой информации. Надежнее все метаданные тоже шифровать.
Конечно, тогда возникает вопрос, а как выбрать сообщения по дате? А никак, можно хранить их под порядковыми номерами и запрашивать диапазон номеров с клиента.
> Действительно, можно создать таблицу специально чтобы только хранить id, а ящики Inbox и Outbox будут хранить ещё и всё остальное (автора, контент, дату и т.д.).
Еще можно рассмотреть вариант - добавить в сообщение внутренний id, который генерируется на клиенте, шифруется и не виден серверу. При редактировании сообщения мы просто посылаем второе сообщение с таким же внутренним id, и контакт понимает, что оно было отредактировано.
> Я уже немного знаком с ним, но почему-то даже не могу придумать функцию которая будет шифровать сообщения.
Поискать готовую в библиотеке openssl: http://php.net/manual/ru/book.openssl.php
Вот статья например https://www.devco.net/archives/2006/02/13/public_-_private_key_encryption_using_openssl.php - можно то же самое делать с использованием функций openssl.
Погугли по "openssl encrypt data asymmetric"
Также, можно посмотреть протоколы Tox, Signal, и расширение OTR для Jabber и посмотреть как поступают они.
> Меня сначала смутило что без js тогда не будет работать приложение,
Чтобы приложение работало без JS, мы должны доверить операции шифрования/расшифровки (и все наши ключи) серверу. То есть поступиться безопасностью.
Также, наверняка ради более высокой защищенности ты захочешь кроме сайта сделать приложение, например, на Electron (так как код на сайте легко подменить, взломав сервер) - в этом случае проблем с отсутствием JS не будет.
То есть чтобы работать без JS, нужно снизить степень защищенности и доверять серверу.
> У меня элемент постоянно обновляется и постоянно нужно ставить новый обработчик.
Покажи тогда код, так как по моему ты просто что-то неправильно делаешь.
Я тут не вижу проблемы. Вот допустим, у нас есть кнопка на странице. Мы нашли ее, поставили на нее обработчик DOM события и больше не добавляем. Или мы создаем кнопку, вставляем в DOM, ставим один раз обработчик и больше не добавляем его. Не важно, контроллер это или view делает, лишь бы DOM-обработчик ставился один раз. Нужно это так спроектировать. MVC тут вообще не при чем.
Обработчик можно снимать в том случае, если например мы хотим "отцепить" виджет от DOM, но я не представляю, когда такое может понадобиться. Обычно мы либо 1 раз "прицепляем" виджет к существующему DOM и никогда не отцепляем, либо виджет сам создает свой DOM, а при уничтожении уничтожает и свой DOM.
>>либо же (если есть много однотипных элементов) выгоднее ставить не много обработчиков, а один обработчик на родительский элемент и ловить всплывающие снизу дерева DOM события.
> Вот так https://jsfiddle.net/jsqt57hz/2/ ?
да. Это обычно применяют для каких-то списков, где много однотипных элементов.
> А я приводил в пример такой вариант, вы сказали что у виджета может быть свой обработчик событий:
Когда я говорил, про "свои" события, я имел в виду систему, когда view сам ставит DOM-обработчик (например, клика на контакт в списке), обрабатывает это событие и генерирует свое, искуственное событие вроде onContactSelect. И контроллер подписывается именно на это искуственное событие, а не лезет в DOM.
То есть view в этом случае скрывает (абстрагирует), откуда берется это событие, от клика мышью, нажатия горячей клавиши или еще чего-то. Просто - у нас есть событие выбора контакта (не клика мышью на DOM элемент, а именно выбора контакта). При таком подходе можно полностью инкапсулировать (скрыть) работу с DOM внутри view, так что другие классы об этом DOM ничего не знают. Тогда при правке верстки изменения ограничиваются view и дальше не вылезают. Но такая абстракция может увеличить объем кода.
> Не выравнивание, а опускание скролла сообщений до последнего сообщения, если я правильно понял терминологию.
Это лучше делать через JS с помощью scrollTop. Его можно ставить в значение scrollHeight - clientHeight. Если хочется без JS, то да, можно просто в конец списка сообщений засунуть якорь, но это ненадежно, так как прокрутиться может еще что-нибудь, лучше наверно так не делать и без JS ничего не прокручивать (либо можно сделать ифрейм с сообщениями, и в нем якорь в конце списка сообщений).
Есть вещи, которые без JS реализовать нормально нельзя - лучше не пытаться реализовывать их через какие-то сложные ненадежные костыли, а подумать над альтернативой. Ну например, вообще убрать внутреннюю прокрутку в списке сообщений или выводить меньше сообщений, чтобы их не надо было прокручивать. Или сделать альтернативный упрощенный интерфейс.
> Заодно можно сделать и сортировку контактов по последним полученным сообщениям.
Через группировку это будет неэффективно, так как будет обзодиться большое число записей (все сообщения для каждого контакта). Такую сортировку лучше сделать денормализацией, добавив поле lastMessageTime в таблицу контактов. Опять же, стоит помнить что это лишняя незащищенная информация.
Я еще хочу предупредить, что если на сервере хранить в открытую свойства сообщений (кто, кому, когда что отправил), это опять же снижает защищенность и повышает риск утечки данных. Ну и правительства тоже заинтересованы в получении такой информации. Надежнее все метаданные тоже шифровать.
Конечно, тогда возникает вопрос, а как выбрать сообщения по дате? А никак, можно хранить их под порядковыми номерами и запрашивать диапазон номеров с клиента.
> Действительно, можно создать таблицу специально чтобы только хранить id, а ящики Inbox и Outbox будут хранить ещё и всё остальное (автора, контент, дату и т.д.).
Еще можно рассмотреть вариант - добавить в сообщение внутренний id, который генерируется на клиенте, шифруется и не виден серверу. При редактировании сообщения мы просто посылаем второе сообщение с таким же внутренним id, и контакт понимает, что оно было отредактировано.
> Я уже немного знаком с ним, но почему-то даже не могу придумать функцию которая будет шифровать сообщения.
Поискать готовую в библиотеке openssl: http://php.net/manual/ru/book.openssl.php
Вот статья например https://www.devco.net/archives/2006/02/13/public_-_private_key_encryption_using_openssl.php - можно то же самое делать с использованием функций openssl.
Погугли по "openssl encrypt data asymmetric"
Также, можно посмотреть протоколы Tox, Signal, и расширение OTR для Jabber и посмотреть как поступают они.
> Меня сначала смутило что без js тогда не будет работать приложение,
Чтобы приложение работало без JS, мы должны доверить операции шифрования/расшифровки (и все наши ключи) серверу. То есть поступиться безопасностью.
Также, наверняка ради более высокой защищенности ты захочешь кроме сайта сделать приложение, например, на Electron (так как код на сайте легко подменить, взломав сервер) - в этом случае проблем с отсутствием JS не будет.
То есть чтобы работать без JS, нужно снизить степень защищенности и доверять серверу.
> У меня элемент постоянно обновляется и постоянно нужно ставить новый обработчик.
Покажи тогда код, так как по моему ты просто что-то неправильно делаешь.
Я тут не вижу проблемы. Вот допустим, у нас есть кнопка на странице. Мы нашли ее, поставили на нее обработчик DOM события и больше не добавляем. Или мы создаем кнопку, вставляем в DOM, ставим один раз обработчик и больше не добавляем его. Не важно, контроллер это или view делает, лишь бы DOM-обработчик ставился один раз. Нужно это так спроектировать. MVC тут вообще не при чем.
Обработчик можно снимать в том случае, если например мы хотим "отцепить" виджет от DOM, но я не представляю, когда такое может понадобиться. Обычно мы либо 1 раз "прицепляем" виджет к существующему DOM и никогда не отцепляем, либо виджет сам создает свой DOM, а при уничтожении уничтожает и свой DOM.
>>либо же (если есть много однотипных элементов) выгоднее ставить не много обработчиков, а один обработчик на родительский элемент и ловить всплывающие снизу дерева DOM события.
> Вот так https://jsfiddle.net/jsqt57hz/2/ ?
да. Это обычно применяют для каких-то списков, где много однотипных элементов.
> А я приводил в пример такой вариант, вы сказали что у виджета может быть свой обработчик событий:
Когда я говорил, про "свои" события, я имел в виду систему, когда view сам ставит DOM-обработчик (например, клика на контакт в списке), обрабатывает это событие и генерирует свое, искуственное событие вроде onContactSelect. И контроллер подписывается именно на это искуственное событие, а не лезет в DOM.
То есть view в этом случае скрывает (абстрагирует), откуда берется это событие, от клика мышью, нажатия горячей клавиши или еще чего-то. Просто - у нас есть событие выбора контакта (не клика мышью на DOM элемент, а именно выбора контакта). При таком подходе можно полностью инкапсулировать (скрыть) работу с DOM внутри view, так что другие классы об этом DOM ничего не знают. Тогда при правке верстки изменения ограничиваются view и дальше не вылезают. Но такая абстракция может увеличить объем кода.
> Не выравнивание, а опускание скролла сообщений до последнего сообщения, если я правильно понял терминологию.
Это лучше делать через JS с помощью scrollTop. Его можно ставить в значение scrollHeight - clientHeight. Если хочется без JS, то да, можно просто в конец списка сообщений засунуть якорь, но это ненадежно, так как прокрутиться может еще что-нибудь, лучше наверно так не делать и без JS ничего не прокручивать (либо можно сделать ифрейм с сообщениями, и в нем якорь в конце списка сообщений).
Есть вещи, которые без JS реализовать нормально нельзя - лучше не пытаться реализовывать их через какие-то сложные ненадежные костыли, а подумать над альтернативой. Ну например, вообще убрать внутреннюю прокрутку в списке сообщений или выводить меньше сообщений, чтобы их не надо было прокручивать. Или сделать альтернативный упрощенный интерфейс.
> Заодно можно сделать и сортировку контактов по последним полученным сообщениям.
Через группировку это будет неэффективно, так как будет обзодиться большое число записей (все сообщения для каждого контакта). Такую сортировку лучше сделать денормализацией, добавив поле lastMessageTime в таблицу контактов. Опять же, стоит помнить что это лишняя незащищенная информация.
Тут нет готовых паттернов. Судя по многочисленным намекам в задаче, предлагается использовать наследование.
AnswerInterface никуда не годится, так как в нем нет методов. Как ты им собрался пользоваться?
В checkAnswer ничего не передается - что он проверяет? Та же проблема в CalcScore.
SaveAndGEtResult явно должен быть в контроллере, а не в модели упражнения Exercise.
В твоем коде я вижу проблемные места - например, статический метод работы с БД, который не позволит тут использовать DI (урок по DI https://github.com/codedokode/pasta/blob/master/arch/di.md ). Мануалов по Юи перечитался?
Ну и по ощущениям, у тебя тут многовато интерфейсов, хотя не могу найти, почему бы это было плохо.
>>1029194
При заходе на несущ. страницу надо показывать страницу 404, а не редиректить. Редирект значит "эта страница есть, но по другому адресу".
Логгировать очень просто - пишешь данные в файл или вставляешь строку в таблицу в БД. Не понял, что именно тут непонятно. Ну и тебе правильно написали, Апач умеет логгировать такие обращения.
> редирект понятно через какой-нибудь htaccess можно сделать, но как это совместить с записью в бд?
htaccess такого не позволяет, я думал ты в PHP такие запросы обрабатвыаешь. То есть перенаправляешь все запросы на PHP-код и в нем уже смотришь.
>>1029149
> Как передавать в конструктор значение с поля класса?
Обычным образом. Какого-то специального синтаксиса для этого нет.
> Мне лень в каждый объект ручками все добавлять, когда все эти значения и так есть в классе.
Проблема в том, что ты там накопипастил 2 страницы кода, и это неправильно. Нужно переделать этот код, чтобы он был без копипасты.
Прокомментирую еще:
> public $endStavka; // окончательная ставка, вычисляется через функцию EndStavka
Не стоит хранить данные, которые вычисляются из других полей, так как в этом случае ты обязан их обновлять при изменении любого из исходных полей и тут легко что-то пропустить. Храни только исходные данные, а вычисляемые не храни вообще. То есть сделай метод для вычисления зарплаты.
Ты задаешь при наследовании свойства данной профессии. Но это никак не документировано и никак не проверяется. Лучше использовать абстрактные функции, чтобы нельзя было унаследоваться от Worker и забыть что-то задать.
Также, у тебя список работников почему-то жестко прописан в департаменте. Не надо так, нужно сделать отдельно департамент (с методом принятия данного работника на работу) и отдельно список работников, и функция, которая по этому списку создает работников и вставляет в департамент. И тогда может быть не понадобится гора кода для заполнения этих свойтсв.
Тут нет готовых паттернов. Судя по многочисленным намекам в задаче, предлагается использовать наследование.
AnswerInterface никуда не годится, так как в нем нет методов. Как ты им собрался пользоваться?
В checkAnswer ничего не передается - что он проверяет? Та же проблема в CalcScore.
SaveAndGEtResult явно должен быть в контроллере, а не в модели упражнения Exercise.
В твоем коде я вижу проблемные места - например, статический метод работы с БД, который не позволит тут использовать DI (урок по DI https://github.com/codedokode/pasta/blob/master/arch/di.md ). Мануалов по Юи перечитался?
Ну и по ощущениям, у тебя тут многовато интерфейсов, хотя не могу найти, почему бы это было плохо.
>>1029194
При заходе на несущ. страницу надо показывать страницу 404, а не редиректить. Редирект значит "эта страница есть, но по другому адресу".
Логгировать очень просто - пишешь данные в файл или вставляешь строку в таблицу в БД. Не понял, что именно тут непонятно. Ну и тебе правильно написали, Апач умеет логгировать такие обращения.
> редирект понятно через какой-нибудь htaccess можно сделать, но как это совместить с записью в бд?
htaccess такого не позволяет, я думал ты в PHP такие запросы обрабатвыаешь. То есть перенаправляешь все запросы на PHP-код и в нем уже смотришь.
>>1029149
> Как передавать в конструктор значение с поля класса?
Обычным образом. Какого-то специального синтаксиса для этого нет.
> Мне лень в каждый объект ручками все добавлять, когда все эти значения и так есть в классе.
Проблема в том, что ты там накопипастил 2 страницы кода, и это неправильно. Нужно переделать этот код, чтобы он был без копипасты.
Прокомментирую еще:
> public $endStavka; // окончательная ставка, вычисляется через функцию EndStavka
Не стоит хранить данные, которые вычисляются из других полей, так как в этом случае ты обязан их обновлять при изменении любого из исходных полей и тут легко что-то пропустить. Храни только исходные данные, а вычисляемые не храни вообще. То есть сделай метод для вычисления зарплаты.
Ты задаешь при наследовании свойства данной профессии. Но это никак не документировано и никак не проверяется. Лучше использовать абстрактные функции, чтобы нельзя было унаследоваться от Worker и забыть что-то задать.
Также, у тебя список работников почему-то жестко прописан в департаменте. Не надо так, нужно сделать отдельно департамент (с методом принятия данного работника на работу) и отдельно список работников, и функция, которая по этому списку создает работников и вставляет в департамент. И тогда может быть не понадобится гора кода для заполнения этих свойтсв.
Потому что обычно ты не можешь что-то передать в аргументы. Вот например array_filter, она принимает на вход функцию и передает в нее элементы массива, и что-то другое ты в аргументы передать не можешь.
Вообще, реши такую задачу. Есть список допустим учеников в массиве - фамилия, оценка. Нужно сделать функции:
- функция, которая возвращает полный список учеников
- функция, которая отбирает учеников по произвольному переданному снаружи критерию
- функция, которая, используя предыдущую функцию, находит всех учеников с оценкой выше определенного значения
>>1028597
У тебя такие аналогии, я надеюсь, они не на твоем жизненном опыте основаны.
>>1028470
Ты должен использовать только те переменные, что есть. Как иначе потом понять твой код?
>>1027651
> Что можно сделать после успешной отправки сообщения?
В мессенджерах они обычно как-то помечаются. Вообще, это зависит от того, как ты свой интерфейс спроектируешь.
> Как-то не хочется оставлять пустую функцию
Не вижу в чем тут проблема.
> Стоит ли так выборочно обрабатывать ошибки? Для пользователя достаточно вывести ошибку соединения, а для разработчиков выбросить в консоль статус и текст ошибки.
Вот по моему неудачно ты обрабатываешь ошибки. Исключения - они ведь для исключительных ситуаций, когда ничего не сделать. Например: отстуствует файл, который должен быть или идет вызов несуществующей функции.
Но сетевые ошибки - это другое дело. Это абсолютно нормальная вещь, что связь может пропасть, сервер перезагрузиться итд. И это должно быть предусмотрено при проектировании. Если у тебя синхронный обмен данными, то можно написать, что не удалось отправить сообщение и предложить отправить еще раз. Если, например, как в скайпе, обмен данными идет в фоне, то при пропаже связи можно менять иконку статуса и визуально помечать пока не отправленные сообщения.
> Почему у меня не вбрасываются эти ошибки (ошибки не появляются в консоле)? Это из-за асинхронного кода?
Это особенности промисов. В then(onFulfilled, onRejected) ты передаешь 2 функции-обработчика, и промис перехватывает любые выброшенные в них исключения и использует это как сигнал об ошибке обработки и режджектит следующий в цепочке промис. Вот пример кода:
// p резолвится в значение 1
var p = new Promise(function (resolve, reject) {
resolve(1);
});
// обработчик выбрасывает исключение, потому p2 реджектится в эту ошибку
var p2 = p.then(function (val) {
throw new Error();
});
Что-то ты не очень знаешь, как работают промисы. Может быть, тебе стоит разобрать пример реализации вот тут: https://www.promisejs.org/implementing/ ?
И еще, напомню, что промисы jQuery не соответствуюют спецификации Promise/A+, которая используется в языке JS. У них свои несовместимые промисы.
И еще, у тебя обработка ошибок странно сделана:
> that.backend.postMessage(to, message, token).then(
> ....
> function(jqXHR, textStatus) {
> ...
> that.backend.handleError(jqXHR, textStatus);
> }
Странно, что backend сначала отдает ошибку тебе, а ты потом ее отдаешь назад в backend. Он наверно и сам бы мог это делать.
Еще, я вижу что у тебя нигде перед классами не написано, за что они отвечают. Я бы советовал тебе писать, в первую очередь для самого себя, чтобы было легко увидеть, у кого какая область ответственности.
> К сожалению, у меня не получилось найти в ejs аналог функции nl2br и при этом чтобы экранировались тэги. В таком случае, будет приемлемым оставить этот костыль?
nl2br не экранирует теги, она только заменяет \n на <br>, если я не путаю.
Насколько я понял, у тебя проблема в том, что ejs экранирует данные и твой <br> выводится как текст? В документации ( https://github.com/mde/ejs/blob/master/docs/syntax.md ) написано что есть 2 вида тегов, один принимают текст, экранируют его и выводят, другой тег принимает HTML код и вставляет его как есть.
В чем именно сложность-то? Можно сделать так <%- convertMessageToHtml(message) %>
> Это нормально, что у меня такая простыня с обработкой ошибок?
Повторяющийся код можно было бы вынести в функцию.
Сам метод public function send($apiMode = false) явно нарушает MVC и представляет пример "толстого" контроллера. Метод отправки должен быть в модели.
Что касается if ($apiMode), тут тоже все как-то странно, тут можно было бы это обобщить, например, сделать специальное исключение ApiError, ловить его и в зависимости от режима выдавать разный ответ.
То есть нет, сделано конечно неудачно. Стена кода какая-то с 7 уровнями вложенности.
> Я плохо понял что такое REST. Это просто архитектура которая позволяет обрабатывать запросы с методами вроде PUT\DELETE?
Это набор принципов, которые можно использовать при проектировании API. Что есть ресурсы (URL), с которыми можно делать разные действия (выражаемые методами). Ну например, PUT /user/ivan/inbox - отправить сообщение Ивану. Лучше посмотреть на примере REST API Яндекс-диска например.
Чистый REST не для каждой задачи хорошо подходит, конечно.
> Я никак не могу придумать как выводить только новые сообщения. Определенно, нужен setTimeout\setInterval чтобы постоянно обновлять данные с сервера, но как при этом выводить только те сообщения которые ещё не выведены в шаблон?
Для этого клиент должен "знать", какие сообщения выведены, и запрашивать с сервера только новые, и добавлять только новые. Чтобы это реализовать, нужно спроектировать изменения в нескольких компонентах:
- придумать поведение пользовательского интерфейса при обновлении данных (как это должно выглядеть)
- в виджете сообщений сделать возможность частичного обновления списка
- где-то в какой-то модели хранить список/диапазон загруженных сообщений
- добавить в АПИ методы и параметры для частичного получения данных
Также, если ты захочешь добавить еще удаление и редактирование сообщений, схему придется еще усложнить.
> Поскольку, я теперь вывожу сообщения за определённый период времени, то если за этот промежуток не было сообщений, при открытии диалога выведиться пустое окно сообщений
Может проще тогда выводить их не по дате, а по количеству? если тебя интересуют именно последние N сообщений.
Также, можно как-то поменять схему. Например, группировать сообщения в группы (по времени) и брать последнюю группу сообщений.
> У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори
Есть вещи, которые нормально без JS не сделать. Ну то есть можно сделать ифрейм с сообщениями, в нем якорь после последнего сообщения - но это усложнит верстку. Может быть, не надо пытаться повторить то же поведение, что есть при наличии JS, а изменить интерфейс - например, вообще убрать прокрутку сообщений или ограничить их количество, чтобы их не надо было прокручивать?
> Не подвергаю ли я пользователей опасности, открывая кукисы для js?
Нет наверно.
> Я сомневаюсь что это будет правильным решением, но с другой стороны не вижу никакой проблемы. Как лучше поступить?
А зачем тебе нужна кука в JS коде? Ведь при отправке аякс-запроса куки и так отправляются на сервер.
И конечно, странно, что у тебя token хранится в view.
> У меня есть переменные, которые пишутся ни как camelCase или snake_case, например moremessages. Я знаю, что это плохой плохой вариант, но мне он кажется вполне читабельным. Лучше будет переимновать?
Да, переименовать. Я бы не сказал, что это читабельно.
Потому что обычно ты не можешь что-то передать в аргументы. Вот например array_filter, она принимает на вход функцию и передает в нее элементы массива, и что-то другое ты в аргументы передать не можешь.
Вообще, реши такую задачу. Есть список допустим учеников в массиве - фамилия, оценка. Нужно сделать функции:
- функция, которая возвращает полный список учеников
- функция, которая отбирает учеников по произвольному переданному снаружи критерию
- функция, которая, используя предыдущую функцию, находит всех учеников с оценкой выше определенного значения
>>1028597
У тебя такие аналогии, я надеюсь, они не на твоем жизненном опыте основаны.
>>1028470
Ты должен использовать только те переменные, что есть. Как иначе потом понять твой код?
>>1027651
> Что можно сделать после успешной отправки сообщения?
В мессенджерах они обычно как-то помечаются. Вообще, это зависит от того, как ты свой интерфейс спроектируешь.
> Как-то не хочется оставлять пустую функцию
Не вижу в чем тут проблема.
> Стоит ли так выборочно обрабатывать ошибки? Для пользователя достаточно вывести ошибку соединения, а для разработчиков выбросить в консоль статус и текст ошибки.
Вот по моему неудачно ты обрабатываешь ошибки. Исключения - они ведь для исключительных ситуаций, когда ничего не сделать. Например: отстуствует файл, который должен быть или идет вызов несуществующей функции.
Но сетевые ошибки - это другое дело. Это абсолютно нормальная вещь, что связь может пропасть, сервер перезагрузиться итд. И это должно быть предусмотрено при проектировании. Если у тебя синхронный обмен данными, то можно написать, что не удалось отправить сообщение и предложить отправить еще раз. Если, например, как в скайпе, обмен данными идет в фоне, то при пропаже связи можно менять иконку статуса и визуально помечать пока не отправленные сообщения.
> Почему у меня не вбрасываются эти ошибки (ошибки не появляются в консоле)? Это из-за асинхронного кода?
Это особенности промисов. В then(onFulfilled, onRejected) ты передаешь 2 функции-обработчика, и промис перехватывает любые выброшенные в них исключения и использует это как сигнал об ошибке обработки и режджектит следующий в цепочке промис. Вот пример кода:
// p резолвится в значение 1
var p = new Promise(function (resolve, reject) {
resolve(1);
});
// обработчик выбрасывает исключение, потому p2 реджектится в эту ошибку
var p2 = p.then(function (val) {
throw new Error();
});
Что-то ты не очень знаешь, как работают промисы. Может быть, тебе стоит разобрать пример реализации вот тут: https://www.promisejs.org/implementing/ ?
И еще, напомню, что промисы jQuery не соответствуюют спецификации Promise/A+, которая используется в языке JS. У них свои несовместимые промисы.
И еще, у тебя обработка ошибок странно сделана:
> that.backend.postMessage(to, message, token).then(
> ....
> function(jqXHR, textStatus) {
> ...
> that.backend.handleError(jqXHR, textStatus);
> }
Странно, что backend сначала отдает ошибку тебе, а ты потом ее отдаешь назад в backend. Он наверно и сам бы мог это делать.
Еще, я вижу что у тебя нигде перед классами не написано, за что они отвечают. Я бы советовал тебе писать, в первую очередь для самого себя, чтобы было легко увидеть, у кого какая область ответственности.
> К сожалению, у меня не получилось найти в ejs аналог функции nl2br и при этом чтобы экранировались тэги. В таком случае, будет приемлемым оставить этот костыль?
nl2br не экранирует теги, она только заменяет \n на <br>, если я не путаю.
Насколько я понял, у тебя проблема в том, что ejs экранирует данные и твой <br> выводится как текст? В документации ( https://github.com/mde/ejs/blob/master/docs/syntax.md ) написано что есть 2 вида тегов, один принимают текст, экранируют его и выводят, другой тег принимает HTML код и вставляет его как есть.
В чем именно сложность-то? Можно сделать так <%- convertMessageToHtml(message) %>
> Это нормально, что у меня такая простыня с обработкой ошибок?
Повторяющийся код можно было бы вынести в функцию.
Сам метод public function send($apiMode = false) явно нарушает MVC и представляет пример "толстого" контроллера. Метод отправки должен быть в модели.
Что касается if ($apiMode), тут тоже все как-то странно, тут можно было бы это обобщить, например, сделать специальное исключение ApiError, ловить его и в зависимости от режима выдавать разный ответ.
То есть нет, сделано конечно неудачно. Стена кода какая-то с 7 уровнями вложенности.
> Я плохо понял что такое REST. Это просто архитектура которая позволяет обрабатывать запросы с методами вроде PUT\DELETE?
Это набор принципов, которые можно использовать при проектировании API. Что есть ресурсы (URL), с которыми можно делать разные действия (выражаемые методами). Ну например, PUT /user/ivan/inbox - отправить сообщение Ивану. Лучше посмотреть на примере REST API Яндекс-диска например.
Чистый REST не для каждой задачи хорошо подходит, конечно.
> Я никак не могу придумать как выводить только новые сообщения. Определенно, нужен setTimeout\setInterval чтобы постоянно обновлять данные с сервера, но как при этом выводить только те сообщения которые ещё не выведены в шаблон?
Для этого клиент должен "знать", какие сообщения выведены, и запрашивать с сервера только новые, и добавлять только новые. Чтобы это реализовать, нужно спроектировать изменения в нескольких компонентах:
- придумать поведение пользовательского интерфейса при обновлении данных (как это должно выглядеть)
- в виджете сообщений сделать возможность частичного обновления списка
- где-то в какой-то модели хранить список/диапазон загруженных сообщений
- добавить в АПИ методы и параметры для частичного получения данных
Также, если ты захочешь добавить еще удаление и редактирование сообщений, схему придется еще усложнить.
> Поскольку, я теперь вывожу сообщения за определённый период времени, то если за этот промежуток не было сообщений, при открытии диалога выведиться пустое окно сообщений
Может проще тогда выводить их не по дате, а по количеству? если тебя интересуют именно последние N сообщений.
Также, можно как-то поменять схему. Например, группировать сообщения в группы (по времени) и брать последнюю группу сообщений.
> У меня есть идея как при отключенном js опускать окно диалога до последнего сообщения - использовать якори
Есть вещи, которые нормально без JS не сделать. Ну то есть можно сделать ифрейм с сообщениями, в нем якорь после последнего сообщения - но это усложнит верстку. Может быть, не надо пытаться повторить то же поведение, что есть при наличии JS, а изменить интерфейс - например, вообще убрать прокрутку сообщений или ограничить их количество, чтобы их не надо было прокручивать?
> Не подвергаю ли я пользователей опасности, открывая кукисы для js?
Нет наверно.
> Я сомневаюсь что это будет правильным решением, но с другой стороны не вижу никакой проблемы. Как лучше поступить?
А зачем тебе нужна кука в JS коде? Ведь при отправке аякс-запроса куки и так отправляются на сервер.
И конечно, странно, что у тебя token хранится в view.
> У меня есть переменные, которые пишутся ни как camelCase или snake_case, например moremessages. Я знаю, что это плохой плохой вариант, но мне он кажется вполне читабельным. Лучше будет переимновать?
Да, переименовать. Я бы не сказал, что это читабельно.
Тут написано http://php.net/manual/ru/language.variables.scope.php
>>1026920
Рисуют дизайн в графическом редакторе, а затем его верстают, то есть переводят в HTML/CSS/картинки. Браузер фотошопные файлы не отображает, и они фиксированного размера, не подстраиваются под размер экрана например. В отличие от HTML/CSS.
То есть фотошопный файл - это просто макет который дизайнер отдает верстальщику в работу. Фотошоп конечно не обязателен, можно и на бумажке нарисовать иногда.
>>1026318
В АПИ по идее форм нет. Возможно, тебе лучше перенести валидацию с формы на модель - то есть мы принимаем данные от формы/АПИ, вбиваем их в объект-модель и отдаем его на проверку. Если все ок - сохраняем, если нет - выводим/возвращаем ошибку.
Также, в Юи есть "сценарии" - ты можешь отключать часть полей и проверок. Ты мог бы сделать одну форму и несколько сценариев для разных случаев.
Наверно, тебе подойдут сценарии. Погугли.
>>1026257
В фронт-контроллере (или входном скрипте). Хочу только предупредить, что сессии плохо подходят для авторизации так как умирают через 30 минут неактивности.
> И где проверять может ли пользователь находиться на странице, private метод контроллера checkAuth() в каждом экшне?
Можно метод в базовом контроллере, можно отдельный класс для этого сделать.
>>1026198
Я Юи2 не использовал, так что сказать, увы, ничего не могу.
Тут написано http://php.net/manual/ru/language.variables.scope.php
>>1026920
Рисуют дизайн в графическом редакторе, а затем его верстают, то есть переводят в HTML/CSS/картинки. Браузер фотошопные файлы не отображает, и они фиксированного размера, не подстраиваются под размер экрана например. В отличие от HTML/CSS.
То есть фотошопный файл - это просто макет который дизайнер отдает верстальщику в работу. Фотошоп конечно не обязателен, можно и на бумажке нарисовать иногда.
>>1026318
В АПИ по идее форм нет. Возможно, тебе лучше перенести валидацию с формы на модель - то есть мы принимаем данные от формы/АПИ, вбиваем их в объект-модель и отдаем его на проверку. Если все ок - сохраняем, если нет - выводим/возвращаем ошибку.
Также, в Юи есть "сценарии" - ты можешь отключать часть полей и проверок. Ты мог бы сделать одну форму и несколько сценариев для разных случаев.
Наверно, тебе подойдут сценарии. Погугли.
>>1026257
В фронт-контроллере (или входном скрипте). Хочу только предупредить, что сессии плохо подходят для авторизации так как умирают через 30 минут неактивности.
> И где проверять может ли пользователь находиться на странице, private метод контроллера checkAuth() в каждом экшне?
Можно метод в базовом контроллере, можно отдельный класс для этого сделать.
>>1026198
Я Юи2 не использовал, так что сказать, увы, ничего не могу.
>> Меня сначала смутило что без js тогда не будет работать приложение,
>Чтобы приложение работало без JS, мы должны доверить операции шифрования/расшифровки (и все наши ключи) серверу. То есть поступиться безопасностью.
>То есть чтобы работать без JS, нужно снизить степень защищенности и доверять серверу.
Можно сделать режим для шифрования\расшифровки сообщений.
>Также, наверняка ради более высокой защищенности ты захочешь кроме сайта сделать приложение, например, на Electron (так как код на сайте легко подменить, взломав сервер) - в этом случае проблем с отсутствием JS не будет.
>(так как код на сайте легко подменить, взломав сервер)
Пользователя тоже можно взломать и подменить его код.
С одной стороны надежнее будет наложить эту ответственность на себя, но с другой, при шифровании\дешифровке на стороне сервере, данные можно будет перехватить по пути, и ещё надежнее будет предоставить эту возможность самому пользователю.
То есть, при залогинивании, мы так же сделаем режим с включенным js и не будем выдавать кукис с расшифрованным ключем.
Если пользователь сначала залогинелся с включенным js, а потом отключил его, то нужно будет вывести уведомление об отсутствии кукиса, и предложить ему перезалогнититься либо просто ввести пароль.
Иметь собственное приложение - это хорошо.
Если взломать сервер, то может произойти всё что угодно.
>> У меня элемент постоянно обновляется и постоянно нужно ставить новый обработчик.
>Покажи тогда код, так как по моему ты просто что-то неправильно делаешь.
Вот здесь
https://github.com/someApprentice/chat/blob/master/public/js/contacts.js#L71
Я вывожу окно переписки
и вот здесь
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L121-L124
я вывожу форму и ставлю на неё обработчики.
Ну да, здесь можно было сделать обработчик частью отображения, либо просто сделать проверку что элемент уже выведен и ставить его только при создании формы.
>> Меня сначала смутило что без js тогда не будет работать приложение,
>Чтобы приложение работало без JS, мы должны доверить операции шифрования/расшифровки (и все наши ключи) серверу. То есть поступиться безопасностью.
>То есть чтобы работать без JS, нужно снизить степень защищенности и доверять серверу.
Можно сделать режим для шифрования\расшифровки сообщений.
>Также, наверняка ради более высокой защищенности ты захочешь кроме сайта сделать приложение, например, на Electron (так как код на сайте легко подменить, взломав сервер) - в этом случае проблем с отсутствием JS не будет.
>(так как код на сайте легко подменить, взломав сервер)
Пользователя тоже можно взломать и подменить его код.
С одной стороны надежнее будет наложить эту ответственность на себя, но с другой, при шифровании\дешифровке на стороне сервере, данные можно будет перехватить по пути, и ещё надежнее будет предоставить эту возможность самому пользователю.
То есть, при залогинивании, мы так же сделаем режим с включенным js и не будем выдавать кукис с расшифрованным ключем.
Если пользователь сначала залогинелся с включенным js, а потом отключил его, то нужно будет вывести уведомление об отсутствии кукиса, и предложить ему перезалогнититься либо просто ввести пароль.
Иметь собственное приложение - это хорошо.
Если взломать сервер, то может произойти всё что угодно.
>> У меня элемент постоянно обновляется и постоянно нужно ставить новый обработчик.
>Покажи тогда код, так как по моему ты просто что-то неправильно делаешь.
Вот здесь
https://github.com/someApprentice/chat/blob/master/public/js/contacts.js#L71
Я вывожу окно переписки
и вот здесь
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L121-L124
я вывожу форму и ставлю на неё обработчики.
Ну да, здесь можно было сделать обработчик частью отображения, либо просто сделать проверку что элемент уже выведен и ставить его только при создании формы.
>> Я уже немного знаком с ним, но почему-то даже не могу придумать функцию которая будет шифровать сообщения.
>Поискать готовую в библиотеке openssl: http://php.net/manual/ru/book.openssl.php
А шифровать копию сообщения собеседника, если его ключ зашифрован паролем?
как*
но функция которая возвращает окончательную ставку сотрудника работает неправильно, подскажи что не так
А в какой момент ранг появляется в сотруднике? А в какой момент считается endStavka? А в какой момент в поле сотрудника записывается endStavka?
Честно говоря, ничего не понятно. Сам почему не можешь найти? xDebug не настроил?
Хотя. Ошибка в том, что ты создаёшь работника, не передавая ему ранг. Конструктор считает уже конечную ставку с коэффициентом 1, т.к. ранг у тебя не 2 и не 3 (null). Потом ты уже назначаешь работнику ранг (зп после этого, конечно, не пересчитывается) и загоняешь работника в массив.
Ранг присваивается в цикле, после создания объекта,но как заставить работать именно после присвоения ранга я не знаю, только если всегда повторно вызывать метод
Няши,есть задача: распарсить при помощи xgettext все строки и создать словарь, но эта мразь парсит все,что в двойных кавычках. Как заставить эту пиздоту хватать только то, что обрамлено в _("хуй пизда сковорода")?
Что имею: OpenServer 5.2.2, PHP Version 5.5.38
Код скрипта: https://gist.github.com/anonymous/2a2fccdb72f02fef15847fbc633a24aa
Скрипт index.php, рядом с ним папка locale/en_EN/LC_ALL/mydomain.po и mydomain.po
Также есть папка с русскими переводами: locale/ru_RU
Содержимое po файлов: https://gist.github.com/anonymous/677ae340489f3db983c1270b194931b5
mo компилирую при помощи https://po2mo.net/
Практика показала, что локали ru_RU не существует, но есть ru, потому я переименовал папки ru_RU в ru и не помогло - всегда gettext возвращает английский текст.
Пробовал папку LC_ALL переименовывать в LC_MESSAGES - толку никакого.
Причем вся эта залупа никаких ошибок наружу не выдает и просто не работает.
Выебать бы в жопу разработчиков такой хуйни, когда даже в логи ничего не пишется. Сцуко как отладка нахуй виндовс - где происходят неизвестные ошибку.
Надеюсь мудрый анон подскажет где здесь косяк.
Разные вещи, если ты об этом: https://github.com/zendframework/zend-debug
Эта штука по сути var_dump для HTML, но тот же symfony/var-dumper гораздо мощнее. xdebug это PHP расширение на Cи, которое позволяет отслеживать выполнение программы и изменять значения переменных во время исполнения кода. Пользуются им обычно через IDE.
>>1026198
Я не ОП, но то, что описано в статье - всем давно известно, странно что подобная статья тебя останавливает. Мне тоже в Yii не нравятся пустые интерфейсы, их собственные сеттеры/геттеры, доступность Yii::$app отовсюду и прочее, но Yii по-прежнему остаётся инструментом, с помощью которого можно быстро и эффективно решать задачи.
>>1030184
> мразь
> пиздоту
> хуй пизда
Ты из /b вылез?
Если мы не доверяем серверу, то все шифрует клиент. Когда A хочет отправить сообщение пользователю B, он делает 2 копии сообщения, одну шифрует своим открытым ключом (чтобы потом самому ее расшифровать), другую - открытым ключом пользователя B (чтобы ее мог расшифровать пользователь B). После чего отправляет обе копии на сервер. Сервер таким образом, не может подглядеть в содержание сообщений.
Этот же подход позволяет передавать сообщения вообще без сервера, напрямую через p2p.
Возникает вопрос - а где взять открытый ключ (ключи, если устройств несколько) пользователя B? Тут есть 2 варианта: либо сервер ведет реестр открытых ключей и клиент запрашивает его с сервера, либо при добавлении в контакты клиенты обмениваются ключами.
Конечно, в обоих вариантах есть риск, что сервер отдаст вместо ключа пользователя B свой ключ (чтобы иметь возможность расшифровать сообщение). Для предотвращения этого нужно хранить ключи собеседников именно на клиенте (или на сервере, но в зашифрованном виде), и обмениваться ими при добавлении в контакты. Для проверки, что ключ не подменен сервером, некоторые мессенджеры показывают его в графическом виде и люди могут сравнить изображения ключа на своих устройствах.
> Пользователя тоже можно взломать и подменить его код.
Если ты взломал компьютер пользователя, то конечно ты можешь просмотреть все, что у него есть на компьютере, и все что он печатает, включая пароли. Но это не так просто. В случае с сервером - сервер(а) выставлен в публичный интернет и больше возможностей для проведения атаки. Также, правительственным агентам гораздо проще придти в дата-центр и потребовать доступ к серверу, в то время как пользователя сначала надо идентифицировать и узнать, где он живет. И если придут за сервером, то пользователи об этом не узнают, в отличие от случая, когда придут к пользователю.
Наконец, есть еще один важный фактор. Клиент может быть с открытым кодом и его можно проверить. Код на сервере проверить нельзя и что он делает на самом деле, узнать невозможно.
То есть мессенджер с открытым клиентом, который не доверяет серверу (а в идеале еще и который может работать через P2P), гораздо надежнее чем мессенджер, доверяющий серверу. Так как появляется единственная точка отказа, атаковав которую, можно взломать всю сеть. И надо доверять владельцу сервера.
Есть конечно еще промежуточный вариант - когда клиент доверяет серверу, но сервер с открытым кодом и пользователь может поднять свой сервер. Но тут все равно защищенность получается ниже чем у варианта с недоверием серверу.
Если мы не доверяем серверу, то все шифрует клиент. Когда A хочет отправить сообщение пользователю B, он делает 2 копии сообщения, одну шифрует своим открытым ключом (чтобы потом самому ее расшифровать), другую - открытым ключом пользователя B (чтобы ее мог расшифровать пользователь B). После чего отправляет обе копии на сервер. Сервер таким образом, не может подглядеть в содержание сообщений.
Этот же подход позволяет передавать сообщения вообще без сервера, напрямую через p2p.
Возникает вопрос - а где взять открытый ключ (ключи, если устройств несколько) пользователя B? Тут есть 2 варианта: либо сервер ведет реестр открытых ключей и клиент запрашивает его с сервера, либо при добавлении в контакты клиенты обмениваются ключами.
Конечно, в обоих вариантах есть риск, что сервер отдаст вместо ключа пользователя B свой ключ (чтобы иметь возможность расшифровать сообщение). Для предотвращения этого нужно хранить ключи собеседников именно на клиенте (или на сервере, но в зашифрованном виде), и обмениваться ими при добавлении в контакты. Для проверки, что ключ не подменен сервером, некоторые мессенджеры показывают его в графическом виде и люди могут сравнить изображения ключа на своих устройствах.
> Пользователя тоже можно взломать и подменить его код.
Если ты взломал компьютер пользователя, то конечно ты можешь просмотреть все, что у него есть на компьютере, и все что он печатает, включая пароли. Но это не так просто. В случае с сервером - сервер(а) выставлен в публичный интернет и больше возможностей для проведения атаки. Также, правительственным агентам гораздо проще придти в дата-центр и потребовать доступ к серверу, в то время как пользователя сначала надо идентифицировать и узнать, где он живет. И если придут за сервером, то пользователи об этом не узнают, в отличие от случая, когда придут к пользователю.
Наконец, есть еще один важный фактор. Клиент может быть с открытым кодом и его можно проверить. Код на сервере проверить нельзя и что он делает на самом деле, узнать невозможно.
То есть мессенджер с открытым клиентом, который не доверяет серверу (а в идеале еще и который может работать через P2P), гораздо надежнее чем мессенджер, доверяющий серверу. Так как появляется единственная точка отказа, атаковав которую, можно взломать всю сеть. И надо доверять владельцу сервера.
Есть конечно еще промежуточный вариант - когда клиент доверяет серверу, но сервер с открытым кодом и пользователь может поднять свой сервер. Но тут все равно защищенность получается ниже чем у варианта с недоверием серверу.
https://3v4l.org/GNWKP
> сделай функцию countBits, которая принимает на вход число и возвращает число единиц в его двоичном представлении
Тут ведь нужно без циклов через побитовые операторы делать? Не понимаю как сделать, можно подсказку?
clearBit сделан неправильно: clearBit(0, 0b001) должен давать 0.
countBits можно для начала сделать через цикл, а потом почитать вопросы вроде
https://stackoverflow.com/questions/109023/how-to-count-the-number-of-set-bits-in-a-32-bit-integer
http://www.geeksforgeeks.org/count-set-bits-in-an-integer/
https://www.google.ru/search?q=count+bits&newwindow=1&gbv=1&sei=zvV0WdeIC4XI6ATBj6DICg
В рот его топтать, это слишком тяжело - просто взять и установить эту хуету.
Устанавливал на мак.
С горем пополам у меня это получилось, я использовал их Homestead, для которого понадобился Vagrant и VirtualBox
Ну ладно, поставил. Даже создал какой-то сайт по гайдам из документации. Даже понял, куда надо кидать файлики, чтобы с ними работать папка Public в созданном проекте
Но как мне войти в свой проект-то?
Я смог написать php artisan serve и захожу на сайт через localhost:8000/.
Как это пофиксить? Что надо сделать?
Как мне подключиться к БД? Как использовать ебаный phpMyAdmin?
Почему все так сложно, а в документации этого нет?
The Hosts File
You must add the "domains" for your Nginx sites to the hosts file on your machine. The hosts file will redirect requests for your Homestead sites into your Homestead machine. On Mac and Linux, this file is located at /etc/hosts. On Windows, it is located at C:\Windows\System32\drivers\etc\hosts. The lines you add to this file will look like the following:
192.168.10.10 homestead.app
Make sure the IP address listed is the one set in your Homestead.yaml file. Once you have added the domain to your hosts file and launched the Vagrant box you will be able to access the site via your web browser:
http://homestead.app
https://laravel.com/docs/5.4/homestead
--------------------------------------------------------------------------------
ssh https://www.vagrantup.com/docs/cli/ssh.html
sudo apt-get install phpmyadmin
Я толком не смотрел, но с ООП у автора серьёзные проблемы (пик).
>>1030786
Для начинающего гораздо проще встроенный в PHP веб-сервер, который не требует установки и настройки: https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Встроенный-в-php-сервер/
>>1030787
> В рот его топтать, это слишком тяжело - просто взять и установить эту хуету.
Одна строчка в терминале, куда уже проще?
> я использовал их Homestead, для которого понадобился Vagrant и VirtualBox
Для новичка это лишние стены абстракций, зачем они тебе? Читай о том, с чем работаешь и думай, нужно ли оно тебе. Бездумным перепечатыванием команд ничего не добьёшься.
> Я смог написать php artisan serve и захожу на сайт через localhost:8000/.
> Как это пофиксить?
Что фиксить? Команда artisan serve запускает встроенный веб-сервер в PHP, там нет виртуальных хостов как в апаче.
> Как использовать ебаный phpMyAdmin?
Laravel не имеет вообще никакого отношения к phpMyAdmin.
> Как мне подключиться к БД?
> а в документации этого нет?
Вот тут я уже подумал, что ты троллишь. По твоему нежеланию читать документацию и обилию нытья можно однозначно сказать то, что тебе рано лезть во фреймворки.
у меня просто случился бугурт
тяжело это дается как-то
>Одна строчка в терминале, куда уже проще?
а вот ни разу не одна, я часа два устанавливал
к слову, мне кажется, я мог вообще не париться и поставить просто Valet
>Для новичка это лишние стены абстракций, зачем они тебе? Читай о том, с чем работаешь и думай, нужно ли оно тебе. Бездумным перепечатыванием команд ничего не добьёшься.
Полностью согласен. Но я читал документацию с начала. Русскую. Там ребята начали с того, что хорошо было бы поставить homestead.
К слову, я на маке недавно и вполне представляю, как настраивается обычный AMP на винде. А для своих целей, так я бы вообще не парился и поставил Open Server, потому что у меня ничего, кроме самообразования особо-то и нет.
>Что фиксить? Команда artisan serve запускает встроенный веб-сервер в PHP, там нет виртуальных хостов как в апаче.
Ну хорошо, допустим. Но как мою проблему решить, я так и не догнал. У меня не работает http://homestead.app
Точнее, он как бы работает и пишет No input file specified.
>Laravel не имеет вообще никакого отношения к phpMyAdmin.
Ну и что? Я хочу использовать MySQL, а там привык юзать phpMyAdmin. Хотел бы знать, как это использовать в связке с Laravel. Как установить, как начать пользоваться.
>Вот тут я уже подумал, что ты троллишь. По твоему нежеланию читать документацию и обилию нытья можно однозначно сказать то, что тебе рано лезть во фреймворки.
Здесь я просто бомбанул. Все там про БД написано.
>с ООП у автора серьёзные проблемы (пик).
А как для нубов лучше реализовать M в паттерне MVC?
ActiveRecords? Новички в страхе убегут...
В /etc/hosts у меня добавлен 192.168.10.10 homestead.app все по гайду
Толку от этого?
У меня есть проект, который я создал через composer. Но он никак не связан с тем, что в hosts
У меня в шапке сайта есть несколько кнопок, по нажатию которых я перемещаюсь в разные места своего высерасайта. Каждая из кнопок включает свой скрипт, который лежит по адресу php/скриптнейм.php. В каждом скрипте так же прогружается(require) эта самая шапка (файл main.php, из которого я щелкаю по кнопкам), которая лежит в одной директории с папкой php. Проблемы возникают тогда, когда мне нужно из любого из нескольких скриптов вернуться в main.php, либо из какого-либо скрипта переместиться в другой.
В main.php для всех кнопок (на самом деле это ссылки, но неважно) написан путь "php/скриптнейм1.php", "php/скриптнейм2.php" и т.д. Если я, будучи в одном из этих скриптов, захочу переместится в какой-либо из других оставшихся скриптов (или в main.php), браузер пошлет меня нахуй, ибо т.к я нахожусь уже в папке php, ссылку мне нужно задавать относительно нее, а она имеет вид "php/..." (такая же, как была загружена через require 'main.php').
Я бы конечно мог все эти файлы поместить в одну директорию, но так не интересно. Стили тоже не загружаются. Как можно решить данную проблему? Спасибо заранее! надеюсь нормально все объяснил.
Не делай так
http://yournet.kz/blog/project/koncepciya-edinoj-tochki-vxoda
Концепция «единой точки входа»
Может не будешь создавать себе трудности и установишь php и composer на мак. Ларавел устанавливай через композер. Апач не нужен.
Он перебирает элементы массива по индексу, и если оный ключ сего индекса равен нулю, то изымает. Так я задумывал.
попробовал через docker, один хуй не получается
не догоняю, что куда копировать, какие где файлы создавать
я сделал контейнер, все работать должно, куда сайт заливать не понимаю
пиздец, какой же я тупой
>Для начинающего гораздо проще встроенный в PHP веб-сервер, который не требует установки и настройки
Я хочу PhpStorm использовать, хз как там встроенный сервер. Он подойдет?
$actionName = isset($_GET['action']) ? $_GET['action'] : 'index';
Если переданный гет парамент не null, то устанавливаем переменной его значение, иначе - индекс.
Почему условие прописано так? "?", ":" - dgthdst cnfkrbdf.cm
Тебе правильно советуют сделать единую точку входа, и уже в этом скрипте смотреть, какой URL и что надо вызвать. Но советую тебе также почитать про относительные ссылки и научиться собирать любые виды ссылок: https://github.com/codedokode/pasta/blob/master/network/urls.md
Спасибо, туплю-торможу.
Перечитай еще раз мурзилку как пользоваться = и ==
В даблах забыл сравнение кубов анон1 == анон3.
На трипл единственное, что приходит в голову - чтобы строка не была вырвиглазно большой, можно вынести сравнения в отдельные переменные и потом в проверку условия подставлять только их.
Мимо-3-день-в-клубе-кун
Делал по этому мануалу
https://www.jetbrains.com/help/phpstorm/php-built-in-web-server.html#d147912e141
Ну и что? Тут перекатывальщики тредов иногда пытаются всю шапку в заголовок запихнуть
Так в заголовке написано то же самое, что и в сообщении. Я хочу что-нибудь одно.
Помню дрочил задачи по регуляркам уже почти 3 года назад, жаловался другу который уже работал в яндексе или еще где на тот момент, что мол хуево и сложно. Он сказал что нахуй их, они ирл не нужны почти, а если и нужны то простые которые за 3 сек гуглятся по типу https://code.tutsplus.com/tutorials/8-regular-expressions-you-should-know--net-6149
или заменяются знанием вот этой вот хуйни
http://php.net/manual/ru/function.filter-var.php
Но это что касается бекэнда, когда я немного ковырял фронтэнд, там нужны знания регулярок немного, потому что много хуеты с заполнением полей пользователем и прочее.
Не, скорее в галере а собеседовании будет задача с регуляркой в тесте-хуесте. На которой если ты не обосрешься и устроишься, то больше никогда с регулярками не столкнешься.
>Что за галера?
Любая большая контора с кучей кодеров, штатом hr-шлюшек иерархией и прочим. Мб даже автоматизированным собеседованием, когда просто решаешь задачки или тесты проходишь как раз, вместо того что бы разговаривать со своим будущим начальником, как в какой-нибудь веб студии.
Особенно тех, которые ближе к концу.
Какую задачу ты не можешь решить?
Надо раскладывать сложные задачи на подзадачи и решать каждую из них.
Ближе к концу основная задача как бы штаны не обосрать. На нее мозгов не надо.
Почти все, лол.
Вот, например, вот эту.
Как вообще разбивать задачу на несколько маленьких? Я даже не могу придумать алгоритма к этой задаче.
Даа, помню это, на таких задачах тоже сидел по неделе и не прогрессировал тупо чувствуя собственное бессилие. Это оп на самом деле тонкий троль, под видом простеньких задачек на 20 строк засунул пусть и типовые, но сложные алгоритмы, над которыми сотни людей ебутся в попытке их решиь наскоком без гугла.
Я вот сейчас хуй решу наверное опять его.
Попробуй для начала решить её через так называемый "жадный алгоритм".
Это когда ты идешь от больших купюр к меньшим всегда.
Например у тебя сумма в 24650 рублей.
Сначала ты выдаешь пятитысячники если они есть, пока они возможны, потом смотришь что уже не выдать.
Остался остаток 4650, смотришь какие другие купюры идут следом у тебя, если тысячные есть в наличии, то ими выдаешь 4 * 1000, и далее остаток в виде 550 рублей добить.
Сначала напиши например функцию, которой ты будешь передавать сумму которую нужно разменять, число имеющихся купюр 1 номинала, а она тебе будет возвращать значение сколько она смогла их задействовать, и сколько остаток еще нужно сдать купюрами поменьше.
Например: передаешь в неё, что разменять надо 12345 рублей пятитысячными, если в наличии много пятитысячных, то она тебе в ответ: 2, 2345
если у тебя одна пятитысячная, то она тебе: 1, 7345
ну и если нету, то: 0, 12345.
Далее думаю сообразишь, что остаток в виде 2345 можно отдавать опять же этой функции но уже с другими купюрами, и так далее пока всё не сойдется или не сойдется :(
Там я игрался с большим количеством костей в процессе, и ели вардамп раскоментить, то что бы по возрастанию красиво всё выдавало (просто так кароче он там)
Первым аргументом в preg_match() должна идти регулярка, а вторым - строка, к которой применяется регулярка.
Это из-за настройки display_errors = 1 в php.ini. При ее включении, PHP выводит текст ошибки на экран (в данном случае в консоль). Плюс, в командной строке в качестве лога (журнала) ошибок используется стандартный поток ошибок, потому ошибка дополнительно еще раз логгируется в консоль.
В случае использования веб-сервера ошибка будет выводиться один раз на странице и один раз логгироваться в лог-файл сервера.
Исправить сиутацию можно отключив display_errors только для консоли (иначе в браузере тоже перестанет отображаться ошибка). Это можно сделать с помощью настроек в php.ini или ключа командной строки -d error_reportng=0 в настройках, где указывается команда для запуска интерпретатора в командной строке.
>-d error_reportng=0
Это отключит все сообщения об ошибках.
Я же сделал -d log_errors=Off, чтобы лог не велся.
Тройного сравнения нет, потому надо сравнить
(кубик1 == кубик2) && (кубик2 == кубик3)
Для удобства (чтобы if не был гигантским) можно вынести результат сравнения (true/false) в переменную:
$isTripleAnon = ($кубик1 == $кубик2) && ($кубик2 == $кубик3);
$isTripleRobot = ...;
if ($isTripleAnon && $isTRipleRobot) { ... }
Но если это сложно, то можно все в if писать.
У тебя на скриншоте в проверке на трипл почему-то стоит "или" (||) в условии вместо "и".
А вообще, правильно делаешь, что усложняешь задачи.
display_errors конечно: http://php.net/manual/ru/errorfunc.configuration.php#ini.display-errors
Логичнее отключать именно их.
Если да, то подскажите, как мне отправлять $bot->command каждую минуту бесконечно?
Если нет, то подскажите, почему while($i < 300){ $i++; code.... } не работает, а зависает?
>while($i < 300){ $i++; code.... }
http://ideone.com/0rBwBa
У меня не зависает. Ты вопрос неправильно задаешь.
Почему у меня после юнит-теста бд удаляется? Причем похуй успешно или нет.
Все пральна, за собой убирать надо.
При запуске тестов должна создаваться новая бд с фикстурами, а по окончании тестов — удаляться.
Да шучу я, шучу.
Ну на видосах у челика не удаляется ничего после тестов, и да я в phpunit.xml вот такие строчки добавил:
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
Ищи причину ошибки в логе, например. Или выведи их (подробные сообщения об ошибках) на экран.
Народная казахская мудрость
Кто тебе вообще сказал, что будет легко? Приготовься учиться лет 10 до нормального уровня или сразу уёбывай.
Для винды XAMPP сейчас, пожалуй, самый удобный комплект разработчика из подобных "из коробки", юзай.
Нихуя не помогло. Обычные скрипты работают нормально, а вот встроенные в phpstorm сервер никак не хочет работать.
Ты еще расскажи о том, что Денвер в свое время был непопулярным.
ОпенСерверу уже хуй знает сколько лет и пришел он как раз на смену денверу.
>lamp
>не сравнится с этой сборкой по возможностям.
LoL. Прочувствовал расхожее мнение про пхпешников
Зависит от:
- твоего уровня знаний
- объёма, по которому надо искать
- качества поиска
В простом случае это должна делать ровно 1 процедура (или запрос, в случае sqlite) в БД и 15 условно, мамкины оптимизаторы, спокойно строк на рнр
Для того же, для чего в реальной жизни полезны перечисления, то есть, для всего.
Например, результаты запроса из БД (например, список пользователей/страниц/аллахов) в большинстве случаев будет преобразован в массив для удобства работы.
В РНР все запросы от пользователя тоже хранятся в глобальных массивах $_GET и $_POST:
в скрипте myscript.php
по адресу myscript.php?foo=bar&page=2
будет доступен массив
$_GET[
'foo'=>'bar',
'page'=>2,
];
А поле ввода <form action="script.php" method="POST"><input name='myfield'></form>
отправит информацию в массив
$_POST['myfield'];
Вывести массив на страницу можно так:
echo '<pre>'.print_r( $_GET, true ).'<pre>';
более того, на русском и та что есть запаздывает на несколько лет
Вообще-то новые версии выходят каждые пару лет, язык развивается постоянно. Такие реалии.
В чем разница между php и javascript? Это ведь совершенно разные платформы для своих целей, не так ли?
На php можно делать форумы, а javascript это скриптовый язык для страниц? Объясните нуфаку. Я просто вот-вот начну изучать пхп и хочу не обосраться. Да я прекрасно понимаю, что пойму по мере изучения, но можно как нибудь поверхностно описать их работу двумя словами?
PHP работает на сервере: принимает и разбирает пользовательские запросы, работает с БД и сессиями.
Сейчас, в 2009, js тоже пытается это делать (node.js), но основная его роль -- выполнение прямо в браузере клиента: визуально изобразить что-нибудь (меняя html и css у клиента), отправить со страницы запрос к тому же РНР скрипту.
Ну атом подсказывает, правда пришлось расширение добавить
самый простой из всех mvc, достаточно чтобы познакомиться с WebMVC, и потом перейти на тотже Laravel. хотя самому всеравно больше нравится именно Phalcon
Туториалы есть? Туториалов нет. А значит для новичков это крайне плохой вариант. Сравни со слимом https://www.youtube.com/watch?v=RhcQXFeor9g&list=PLfdtiltiRHWGc_yY90XRdq6mRww042aEC&spfreload=10
Это официальная документация, которая есть у всех фреймворков, а не туториалы для ньюфагов с объяснением нюансов. Кроме того все видео на ютубе, которые я только что нашел, двухлетней давности, что многое говорит о его состоянии.
Вот я ньюфаг, выбирал вчера маленький фреймворк, и фалькон был в списке, да. И из-за отсутствия годных туториалов, он пошел нахуй. По слиму же всё есть.
Атом тоже идет нахуй, не может в банальный extends и автокомплит имен файлов. Хоспаде, неужели пхпсторм единственный нормальный вариант.
я не пойму, шутишь ты или нет, вот пошаговый туториал как хелло ворлд сделать
https://olddocs.phalconphp.com/en/3.0.0/reference/tutorial.html
не смотри то что написано olddocs, текущая версия 3.3 полностью совместима с 3.0
вот тебе скелеты под приложения на все случаи жизни https://github.com/phalcon/mvc
просто не понятно, как ты искал, если это не нашел
>пошаговый туториал как хелло ворлд сделать
Вот именно, хеллоу ворлд. А я хочу взять и сделать регистрацию на сайте, с валидацией и прочим CSRF. Зачем мне жрать кактус и гуглить в поисках крупиц информации на эту тему с фальконом, если я просто открою ссылку выше для слима, и там уже всё готовое с пояснением всех мелочей? А если мне не будет понятно, то я просто спрошу в треде, поскольку даже в шапке этот фреймворк рассматривается.
вот тебе псевдо код примерный, страницы каталога товаров
$products = SQL(SELECT * FROM PRODUCTS);
foreach $products as $product {
print product_card
}
а ты ниже смотрел?))) вторая часть туториала про форму регистрации с валидацией?
1) Смотришь делится ли число на 100, если нет -> еррор, если да -> п.2
2) далее смотришь хватает ли у тебя денег выдать, сумма всех купюр сравнивается с запрошенной суммой, если нет -> еррор, если да -> п.3
3) Идешь от большей купюры в меньшую, 23550 - 5000 - 5000, параллельно чекаешь чтобы купюр хватало, ну и тут либо не хватит соток например либо хватит, если нет -> еррор, если да -> то все ок
ну вот и я про то же, фв очень простой, дело освоения пары часов(если знаком с пхп хотябы на 4/10), если не знаком ну 1-2 дня(максимум около недели, зависит от общего понимания программирования и WebMVC паттерна)
Ну ты перебираешь блокноты какие-то.
Из бесплатных IDE можешь ещё помучиться с Eclipse, а так да -- плати за PHPStorm, это норма.
Спасибо анон, добра.
Сам не писал, но почитал документацию сейчас, слим посложнее фалкона будет, да и выглядит слим как странная песочница а не фреймворк, тотже фалкон или ларавел, сразу написано что и как по структуре, есть дефолтный роутинг, который не нужно расписывать(SITEName/ControllerName/ActionName). в фалконе довольно хорошая орм, и querybuilder прекрасный просто. пишется очень легко и проблемы редко возникают с ним.
вообще советую сильно не увлекаться ТОЛЬКО бэкендом, а посмотреть в сторону фронта еще, например Vue или React(ангулар кал)
Я планирую вью использовать.
Интересует момент такой
$bot->command с аргументом, обрабатывая этот аргумент
У меня есть файл styles.css. Проблема в том, что при изменении чего либо в этом файле никаких изменений на странице не следует. Я могу даже весь код из этого файла удалить, и он все равно будет применять те стили, которые я когда-то в нем написал (после изменения файл я сохранял, я не такой тупой).
Это похоже на то, что я просто указал путь к файлу который не изменяется, а к тому файлу, который я изменяю, никаких путей подключения не проложено. Но это не так!. Этот styles.css единственный css файл в моем проекте, и только его удаление приводит к выводу на странице чистого html.
Данную проблему я решил переименовыванием этого файла, и собственно внесение этого нового имени в путь подключения, и это работает. Но я не могу понять почему происходит хуйня, описанная выше (у меня 2 раза такое было). Было у кого нибудь такое?
Хотя сейчас даже при его удалении выводятся его стили.
Ну обычно это кеш браузера, как бы ничего странного. Обновление по ctrl+f5 (без кеша) работает же?
Для того и тред... Двуч образовательный
да но не забывай про м маркетинг , так как и все мвц фреймворки по факту строго не могут быть в полной мере мвц из за особенностей протокола , но это не мешает фиигачить на сайтах слово мвц верно?
алсо покажи мне ещё 1 фреймворк который надо устанавливать через php.ini в лучшем случае а то и компилить с его
ну это типа их плюс, что они написали свой фреймворк не на относительно-медленном интерпретируемом языке, а на быстром компилируемом.
Но чё-т после того, как недавно понадобилось что-то на их сайте, а он лежал лёжа несколько часов или даже дней подряд, мне чё-т расхотелось. Пусть сами свой велосипед крутят, на здоровье, а для меня РНР 7.1++ и так достаточно производительный.
Ну и на старте проекта вся эта избыточная оптимизация не в плюс, да ещё и хостинг надо отдельный искать под это дело. В общем, задумка хорошая, но спасибо, не ннада
использую фалкон, конкретно как апишку для фронта на реакте, он быстро позволяет реализовать нормальную апишку
>Можно создать отдельный класс
и это норма, если я в методе этого класса буду отправлять mime заголовок чтобы отдавалась картинка и писать код каптчи в сессию?
Никакие, почитай migration guide для PHP 7.0 и 7.1 на php.net или выжимки вроде этих:
- https://github.com/tpunt/PHP7-Reference
- https://github.com/tpunt/PHP7-Reference/blob/master/php71-reference.md
Например я написал автолоад через
spl_autoload_register
В нем указал 1 папку с файлами, допустим это папка Core
Теперь у меня подгружаются Классы из папки Core
Но как использователь неймспейсы вместе с этим всем? Я проставил классам неймспейсы, и всё сломалось.
Классу роутер который лежит в Core/Router.php например я пишу namespace Core;
Но если я пишу в файле индекс, который лежит снаружи папки Core такую штуку как:
use Core\Router;
то всё ломается. Не понимаю чего-то.
Почитай урок про автозагрузку и неймспейсы https://github.com/codedokode/pasta/blob/master/php/autoload.md
Есть, там ссылка на русскую версию.
кто-нибудь может подсказать:
в PHP 7.1 на этапе исполнения есть ли какая-то разница
между [] и array() //для совместимости со старым PHP5 ?
ну для выполнения на РНР7 или 7.1 будет какая-то разница, или нет (просто написание)?
Для ответа на твой вопрос можно использовать расширение vld. Оно показывает набор инструкций, в которые превращается PHP код после компиляции (выполнять код напрямую неэффективно, потому сначала PHP его компилирует в более удобный для него вид).
Информации про это расширение на русском мало:
- рус https://habrahabr.ru/company/mailru/blog/305906/
- рус https://habrahabr.ru/post/211156/
- англ https://derickrethans.nl/more-source-analysis-with-vld.html
Запустим 2 варианта кода и посмотрим на результат компиляции:
php -dvld.active=1 -r '$a = array();'
INIT_ARRAY ~0
ASSIGN !0, ~0
RETURN null
php -dvld.active=1 -r '$a = [];'
INIT_ARRAY ~0
ASSIGN !0, ~0
RETURN null
результат в PHP5, как мы видим, идентичен.
Также, VLD-дизассемблер есть на сайте 3v4l.org, там я тоже попробовал сделать 2 варианта кода:
https://3v4l.org/lKUHM/vld#output
https://3v4l.org/fnVqn/vld#output
Видно, что в PHP7 что-то оптимизировали и теперь такой же код компилируется в две инструкции вместо трех.
Но вообще, даже если бы разница и была, не стоит о ней беспокоиться, это вряд ли будет заметно на общем времени выполнения программы.
Для ответа на твой вопрос можно использовать расширение vld. Оно показывает набор инструкций, в которые превращается PHP код после компиляции (выполнять код напрямую неэффективно, потому сначала PHP его компилирует в более удобный для него вид).
Информации про это расширение на русском мало:
- рус https://habrahabr.ru/company/mailru/blog/305906/
- рус https://habrahabr.ru/post/211156/
- англ https://derickrethans.nl/more-source-analysis-with-vld.html
Запустим 2 варианта кода и посмотрим на результат компиляции:
php -dvld.active=1 -r '$a = array();'
INIT_ARRAY ~0
ASSIGN !0, ~0
RETURN null
php -dvld.active=1 -r '$a = [];'
INIT_ARRAY ~0
ASSIGN !0, ~0
RETURN null
результат в PHP5, как мы видим, идентичен.
Также, VLD-дизассемблер есть на сайте 3v4l.org, там я тоже попробовал сделать 2 варианта кода:
https://3v4l.org/lKUHM/vld#output
https://3v4l.org/fnVqn/vld#output
Видно, что в PHP7 что-то оптимизировали и теперь такой же код компилируется в две инструкции вместо трех.
Но вообще, даже если бы разница и была, не стоит о ней беспокоиться, это вряд ли будет заметно на общем времени выполнения программы.
Спасибо, буду пробовать
>не стоит о ней беспокоиться, это вряд ли будет заметно на общем времени выполнения программы.
вы совершенно правы, разве что для оптимизации узких мест, потому и спросил
>>1032278
Во-первых, в MVC логично разделить генерацию картинки и ее отдачу. Генерирует картинку класс капчи, а отдает ее и добавляет нужные заголовки контроллер капчи.
Куда поместить класс, генерирующий картинку? Такие классы называют сервисы (или хелперы), логично поместить его в папку App/Service или App/Helper.
А что-то запрещает реализовать MVC в Ларавеле и поместить бизнес-логику в отдельные классы?
Ничто не запрещает, только MVC оно от этого не станет, т.к. бизнес-логика должна быть не в "отдельных классах", а в моделях
Так а чем эти "отдельные" классы отличаются от "модели"? У тебя по моему путаница в терминологии.
В исходном MVC, если я не ошибаюсь, моделью называют часть приложения, содержащую бизнес-логику. Чем "отдельные" классы не соответствуют этому понятию?
Также, иногда "моделью" называют класс, представляющий какую-то сущность: модель Поста, модель Пользователя.
В Симфони например вообще классов с названием "модель" нет.
Что ты подразумеваешь под "моделью"?
Решаю задачку на проверку телефонов
http://archive-ipq-co.narod.ru/l1/regexp.html
Какой метод и как мне использовать, чтобы сформировать новый массив просто с цифрами, чтобы потом отсортировать номера?
match_all через цикл я прогоняю в новый массив, но он туда вписывает ересь на пиках.
Может я пропустил что-то?
>Что ты подразумеваешь под "моделью"?
Класс содержащий бизнес-логику. А ларавел под моделью подразумевает класс являющийся ссылкой на таблицу БД, а классы в которых должна быть логика, называет контроллерами
А как делается "или" чтобы стоял вначале?
Типа ab?c но только чтобы выбирал между 7 и 8 вначале.
Вроде воспользовался. Другое дело, что эта функция возвращает строку, а не присваивает ее. Попробуй сдампить implode(parts)
http://ideone.com/BgpC6G
Твое регулярное выражение ищет просто одну цифру в любом месте строки. Не удивительно, что у тебя каждое число помещается в массив $совпаден(ие)ий.
Тебе нужно добавить в регулярное выражение метасимвол означающий повторение один или несколько раз +
http://php.net/manual/ru/regexp.reference.meta.php
>+ квантификатор, означающий 1 или более вхождений
Ещё ты при каждом обходе итерации цикла выводишь массив совпадений, а не выводишь его один раз при завершении цикла.
Почитай ещё про оформление кода >>1019303
>>1032334
http://php.net/manual/ru/regexp.reference.alternation.php
Учти, что если тебе нужен альтернативный выбор не на всём регулярном выражении, а только на группе символов, тебе следует использовать подмаску.
http://php.net/manual/ru/regexp.reference.subpatterns.php
>1. Локализирует набор альтернатив. Например, шаблон cat(aract|erpillar|) соответствует одному из слов "cat", "cataract" или "caterpillar". Без использования скобок он соответствовал бы строкам "cataract", "erpillar" или пустой строке.
>>1032354
Почему ты пользуешься функцией preg_split, когда для нахождения совпадений есть preg_match?
http://php.net/manual/ru/function.preg-match.php
Функция implode() объединяет массив в строку, а ты пытаешься передать в эту функцию строку.
http://php.net/manual/ru/function.implode.php
>>1032381
Как неожиданно, но чтобы присвоить нужно воспользоваться оператором присваивания =
$variable = implode(...);
Твое регулярное выражение ищет просто одну цифру в любом месте строки. Не удивительно, что у тебя каждое число помещается в массив $совпаден(ие)ий.
Тебе нужно добавить в регулярное выражение метасимвол означающий повторение один или несколько раз +
http://php.net/manual/ru/regexp.reference.meta.php
>+ квантификатор, означающий 1 или более вхождений
Ещё ты при каждом обходе итерации цикла выводишь массив совпадений, а не выводишь его один раз при завершении цикла.
Почитай ещё про оформление кода >>1019303
>>1032334
http://php.net/manual/ru/regexp.reference.alternation.php
Учти, что если тебе нужен альтернативный выбор не на всём регулярном выражении, а только на группе символов, тебе следует использовать подмаску.
http://php.net/manual/ru/regexp.reference.subpatterns.php
>1. Локализирует набор альтернатив. Например, шаблон cat(aract|erpillar|) соответствует одному из слов "cat", "cataract" или "caterpillar". Без использования скобок он соответствовал бы строкам "cataract", "erpillar" или пустой строке.
>>1032354
Почему ты пользуешься функцией preg_split, когда для нахождения совпадений есть preg_match?
http://php.net/manual/ru/function.preg-match.php
Функция implode() объединяет массив в строку, а ты пытаешься передать в эту функцию строку.
http://php.net/manual/ru/function.implode.php
>>1032381
Как неожиданно, но чтобы присвоить нужно воспользоваться оператором присваивания =
$variable = implode(...);
Как выше обяснили это браузер кеширует стили. И например он зашел на твой сайт hueta.loc, скачал твой style.css и всё. Потом если ты вносишь правки в стили, но может смотреть что ситил уже скачаны и подгружать те что скачивал когда-то давно.
Причем если ты шарящий чел, то какие-нибудь клиенты нихуя не такие и что бы избежать того, что бы отвечать в последствии на звонки с разъяснениями ЭС как доллар и нажмите CTRL+F5, ты в шапке или где у тебя там подгружается стиль дописывай ему версию.
<link rel="stylesheet" type="text/css" href="style.css?ver=111" />
А после того как внес изменения в файл то эту версию в шапке обновляй
<link rel="stylesheet" type="text/css" href="style.css?ver=112" />
Браузеры всех кто зайдет после этого автоматически будут обязаны скачать обновленный файл.
>бя не нашел. Давно пишу на ПОХАПЕ различные темы и плагины на продажу (wordpress, themeforest). Общаюсь с клиентами каждый день, работаю в качес
Очень интересно было бы кулстори про themeforest послушать. А дизайн тем сами пилите? Или просто сотрудничаете с дизайнерами?
отвечу так: почему бы и нет?
в свое время ларавел,вуе,реакт,ангулар,фалкон сидел тыкал как хобби, потом уже пилил коммерс проекты на них
Я придумал алгоритм шифрования, но у меня есть несколько вопросов
При регистрации пользователя мы генерируем закртый\открытый ключ
$privateKey = openssl_pkey_new(array(
"digest_alg" => $method,
"private_key_bits" => 4096
));
$publicKey = openssl_pkey_get_details($privateKey)['key'];
Закрытый ключ шифруем паролем
$encryptedKey = openssl_encrypt($privateKey, $method, str2hex($password));
И помещаем их в БД
http://php.net/manual/ru/function.openssl-get-cipher-methods.php#refsect1-function.openssl-get-cipher-methods-examples
Почему нету метода RSA? Однако, в опциях создания ключа можно указать этот тип Что это вообще может значить??. Эти все методы сделаны на его основе?
Какой метод лучше выбрать?
http://php.net/manual/ru/function.openssl-public-encrypt.php#118466
В комментариях сказано, что RSA начинает устаревать и пора переходить на ECDH вместе с EdDSA. Что вы думаете по этому поводу?
Насколько я помню, протокол Диффи - Хеллмана генерирует общий ключ на основе закрытых\открытых ключей. Можно ли сказать, что этот протокол приводит асимметричное шифрование к симметричному?
Эллиптические кривые только добавляют надёжности, я правильно понимаю?
Такой алгоритм подошел бы если бы мы реализовывали вариант с шифрованием сообщений конференции общим ключем.
Далее
Сообщения шифруются но основе открытых ключей собеседников
// Ничего особенно за исключением опции добавления OPENSSL_PKCS1_OAEP_PADDING,
// которое рекомендуется из комментария выше
openssl_public_encrypt($message, $crypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
Расшифровка происходит аналогичным способом
openssl_private_decrypt($message, $decrypted, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
Остается только найти js библиотеку для шифровки\дешифровки аналогичным способом.
Я нашел вот эту http://www-cs-students.stanford.edu/~tjw/jsbn/ , но я не уверен что библиотека которая содержится в PHP использует алгоритм RSA (там какие-то методы (ссылаюсь на тот же вопрос выше о методах)).
К тому же, я не знаю как с помощью RSA т.е. js библиотеки реализующей его расшифровать ключ который мы шифровали паролем, потому что нет возможности получить пары {e, n}\{d, n} из произвольной hex-строки.
Я бы смог решить эту проблему, если бы знал каким образом функция openssl_encrypt() шифрует данные из этой строки. Всё ещё запутан вопросом о методах шифрования Вы случайно не знаете что-нибудь об этом?
http://php.net/manual/ru/function.openssl-encrypt.php
>jsbn.js
>jsbn2.js
Зачем разделять код на две части? Это не более чем прихоть автора?
Я придумал алгоритм шифрования, но у меня есть несколько вопросов
При регистрации пользователя мы генерируем закртый\открытый ключ
$privateKey = openssl_pkey_new(array(
"digest_alg" => $method,
"private_key_bits" => 4096
));
$publicKey = openssl_pkey_get_details($privateKey)['key'];
Закрытый ключ шифруем паролем
$encryptedKey = openssl_encrypt($privateKey, $method, str2hex($password));
И помещаем их в БД
http://php.net/manual/ru/function.openssl-get-cipher-methods.php#refsect1-function.openssl-get-cipher-methods-examples
Почему нету метода RSA? Однако, в опциях создания ключа можно указать этот тип Что это вообще может значить??. Эти все методы сделаны на его основе?
Какой метод лучше выбрать?
http://php.net/manual/ru/function.openssl-public-encrypt.php#118466
В комментариях сказано, что RSA начинает устаревать и пора переходить на ECDH вместе с EdDSA. Что вы думаете по этому поводу?
Насколько я помню, протокол Диффи - Хеллмана генерирует общий ключ на основе закрытых\открытых ключей. Можно ли сказать, что этот протокол приводит асимметричное шифрование к симметричному?
Эллиптические кривые только добавляют надёжности, я правильно понимаю?
Такой алгоритм подошел бы если бы мы реализовывали вариант с шифрованием сообщений конференции общим ключем.
Далее
Сообщения шифруются но основе открытых ключей собеседников
// Ничего особенно за исключением опции добавления OPENSSL_PKCS1_OAEP_PADDING,
// которое рекомендуется из комментария выше
openssl_public_encrypt($message, $crypted, $publicKey, OPENSSL_PKCS1_OAEP_PADDING);
Расшифровка происходит аналогичным способом
openssl_private_decrypt($message, $decrypted, $privateKey, OPENSSL_PKCS1_OAEP_PADDING);
Остается только найти js библиотеку для шифровки\дешифровки аналогичным способом.
Я нашел вот эту http://www-cs-students.stanford.edu/~tjw/jsbn/ , но я не уверен что библиотека которая содержится в PHP использует алгоритм RSA (там какие-то методы (ссылаюсь на тот же вопрос выше о методах)).
К тому же, я не знаю как с помощью RSA т.е. js библиотеки реализующей его расшифровать ключ который мы шифровали паролем, потому что нет возможности получить пары {e, n}\{d, n} из произвольной hex-строки.
Я бы смог решить эту проблему, если бы знал каким образом функция openssl_encrypt() шифрует данные из этой строки. Всё ещё запутан вопросом о методах шифрования Вы случайно не знаете что-нибудь об этом?
http://php.net/manual/ru/function.openssl-encrypt.php
>jsbn.js
>jsbn2.js
Зачем разделять код на две части? Это не более чем прихоть автора?
По опыту работы на Codeigniter скажу что поначалу всё кажется пиздец сложно просто потому что там много всего и с ходу непонятная иерархия и бла бла, но сейчас я бы оповские задачи (которые я на пьюр-пхп ща пытаюсь осилить и сосу в них) по типу студентов на нем худо-бедно накидал буквально за час в силу того что там всё уже написано и на фреймворке хуярить модельки и контроллеры куда проще в итоге.
Понял свою ошибку.
Не использую match, потому что хотел сделать по-своему без сложной регулярки.
Сейчас попробую сделать с ней.
Проверьте пжлст задачки:
Имя кошки - http://ideone.com/9gYMJD
Лев Толстой: http://ideone.com/c7jA9P
Палиндром: http://ideone.com/k76YfM (внезапно на ideone не работает утф-8, на пхптестере вроде все норм)
Заранее пасяб.
Это опять я, короче все збс работает, теперь мне нужно обратиться к свойству объекта, который находится в массиве $workers, а это в cвою очередь свойство объекта $quest, как это реализовывается?
if(isset($_POST['data']) && !empty($_POST['data'])) {
$data = json_encode($_POST['data'], JSON_UNESCAPED_UNICODE);
//DB
$db = getdb();
$query = "INSERT INTO searches (data) VALUES ('$data') RETURNING id";
$result = pg_query($query) or die('Query failed: ' . pg_last_error());
pg_close($db);
echo $result;
}
Так вот какого-то хуя echo $result возвращает мне не id, а какую-то хуйню вроде Resource id #4 или Resource id #5. Какого хуя блядь?
Возвращается резалтсет, как и при обычном селекте. Его надо разобрать
http://php.net/manual/en/pdostatement.fetchall.php
Всё.
А если у меня ключи числами, то будет ли работать действие с указанием элемента массива? Смогу ли я изъять третий по счёту массив, или он будет изничтожать элемент с ключом 3?
Можешь вот так хранить значения если тебе именно нужно обращаться к элементам.
https://ideone.com/5nE5SR
Я задал элементам массива ключи числами, 1, 2 и т.д. Но мне нужно изъять третий элемент массива. Если я напишу unset($arrays{3}); то что будет изъято? Третий по счёту элемент, или тот, что имеет ключ 3? Чому не работает? https://ideone.com/H6wN3Y
Автор: Игорь Симдянов, Дмитрий Котеров Издательство: БХВ-Петербург Год: 2016 Язык: Русский ISBN: 978-5-9775-3725-4 Страниц: 1073
unset($array[0]) - удаляет элемент массива с ключом 0;
if($bills[$z] == 0){
unset($bills[$z]);
}
если элемент массива с ключом $z равен нулю, то удаляем его.
Ты вообще массивы проходил? Нахуя ты сложные задачи лезешь решать, если ты нихуя основ базовых не понимаешь? Как тебе повезло что у нас тут приличный тред, в соседнем ты бы уже захлебнулся в ссанине, смекаешь?
Я их проходил, но давно. Забыл, видать.
Чем раньше начнешь изучать ПОХАПЕ, тем лучше. Даже не обязательно пхп, а просто любой серверный язык программирования, хоть перл, хоть руби, хоть джаваскрипт. Я бы посоветовал изучать что-нибудь асинхронное. Потому что бекэнд намного интереснее фронтэнда (хоть на фронтэнде тоже интересно бывает, иногда).
Фронтэнд это:
Надо сделать обработчик для кнопки, а тут чет анимация хреновая, надо допилить. А тут у формы съехали стили, а тут навбар дергается, надо пофиксить. По сути ты пишешь кучу разных компонентов и правильно подключаешь их к кнопкам и крутилкам, чтобы при нажатии всё правильно крутилось, запрашивало данные с сервера и отображало.
Бекэнд:
Как организовать структуру проекта? Как реализовать алгоритм разбивки по страницам? Как вынести повторяющийся функционал в отдельный класс? Как реализовать rest api? Кеширование? Оптимизировать скорость работы?
И т.д. То есть он интереснее для программистов, да и многие бекэндщики - это матерые фронтэндщики, перекатившиеся на server-side.
>>1032454
Нас 4 человека, дизайн пилит какая-то девушка, я девелопер и саппорт, ещё есть просто типичный саппорт (спасибо что обратились к нам! ваша проблема очень важна для нас!). И есть ещё владелец темы, он занимается маркетингом и немножко даже сам кодит. В одну харю написать что-либо для тимфореста практически нереально.
Про клиентов я писал тут >>935109 >>935303 >>938423. Вкратце, работенка пиздец. Любая хуйня что случится - винят автора темы. Например, купили хостинг за 3 копейки, там оперативной памяти меньше, чем в калькуляторе. А это всё автор виноват! Хуле ты не мог сделать так, чтобы сайт даже на калькуляторе работал?! ИЛИ я поставили плагин и страница вылетает с фатальной ошибкой, скрипты не загружаются. ПОЧЕМУ ВЫ НЕ МОГЛИ СДЕЛАТЬ ЧЕЛОВЕКОПОНЯТНЫЕ СООБЩЕНИЯ ОБ ОШИБКАХ?
Постоянная ебля с обновлениями - Visual Composer обновляется и там постоянно что-то отваливаются, то шорткоды, то настройки pricing table пропадут, то ещё что. WooCommerce обновляется практически каждые две недели, заебешься его шаблоны обновлять. У них там то конфликт с ACF, то ещё че...
+ Конкуренция + у самого themeforest'a ещё и комиссии пиздецовые + он душит своей политикой. Они запускают хуйню, что-то вроде Envato Elements, там оформляешь подписку на год по-моему за 50-60 долларов и весь год качаешь любые темы. Нам это вообще не выгодно, собираемся уйти с тимфореста, открывать свой сайт-магазин.
Чем раньше начнешь изучать ПОХАПЕ, тем лучше. Даже не обязательно пхп, а просто любой серверный язык программирования, хоть перл, хоть руби, хоть джаваскрипт. Я бы посоветовал изучать что-нибудь асинхронное. Потому что бекэнд намного интереснее фронтэнда (хоть на фронтэнде тоже интересно бывает, иногда).
Фронтэнд это:
Надо сделать обработчик для кнопки, а тут чет анимация хреновая, надо допилить. А тут у формы съехали стили, а тут навбар дергается, надо пофиксить. По сути ты пишешь кучу разных компонентов и правильно подключаешь их к кнопкам и крутилкам, чтобы при нажатии всё правильно крутилось, запрашивало данные с сервера и отображало.
Бекэнд:
Как организовать структуру проекта? Как реализовать алгоритм разбивки по страницам? Как вынести повторяющийся функционал в отдельный класс? Как реализовать rest api? Кеширование? Оптимизировать скорость работы?
И т.д. То есть он интереснее для программистов, да и многие бекэндщики - это матерые фронтэндщики, перекатившиеся на server-side.
>>1032454
Нас 4 человека, дизайн пилит какая-то девушка, я девелопер и саппорт, ещё есть просто типичный саппорт (спасибо что обратились к нам! ваша проблема очень важна для нас!). И есть ещё владелец темы, он занимается маркетингом и немножко даже сам кодит. В одну харю написать что-либо для тимфореста практически нереально.
Про клиентов я писал тут >>935109 >>935303 >>938423. Вкратце, работенка пиздец. Любая хуйня что случится - винят автора темы. Например, купили хостинг за 3 копейки, там оперативной памяти меньше, чем в калькуляторе. А это всё автор виноват! Хуле ты не мог сделать так, чтобы сайт даже на калькуляторе работал?! ИЛИ я поставили плагин и страница вылетает с фатальной ошибкой, скрипты не загружаются. ПОЧЕМУ ВЫ НЕ МОГЛИ СДЕЛАТЬ ЧЕЛОВЕКОПОНЯТНЫЕ СООБЩЕНИЯ ОБ ОШИБКАХ?
Постоянная ебля с обновлениями - Visual Composer обновляется и там постоянно что-то отваливаются, то шорткоды, то настройки pricing table пропадут, то ещё что. WooCommerce обновляется практически каждые две недели, заебешься его шаблоны обновлять. У них там то конфликт с ACF, то ещё че...
+ Конкуренция + у самого themeforest'a ещё и комиссии пиздецовые + он душит своей политикой. Они запускают хуйню, что-то вроде Envato Elements, там оформляешь подписку на год по-моему за 50-60 долларов и весь год качаешь любые темы. Нам это вообще не выгодно, собираемся уйти с тимфореста, открывать свой сайт-магазин.
>перл
>руби
Да ну в пизду это хипстерское поделие.
Другой анон
Я пару дней назад решил начать вкатываться в MongoDB и вообще в базы данных. Последний раз я базу данных видел в универе в прошлом году, где мы изучали азы БД на примере Access, а потом MySQL и phpMyAdmin. Мне казалось, что MySQL старьё, и все эти реляционные БД - нахуй их, миром правит NoSQL и JSON. Это всё лирика. Боже, блядь, как же я ошибался. Я за двое суток так люто наебался с Mongo, что теперь я даже лучше говна сожру, чем буду пытаться в этой поделке что-то разобрать. Поставил PostgreSQL, пару часов курения доки, пару вопросов на StackOverflow, 1 вопрос в /pr/ и у меня всё закрутилось-завертелось. Та же хуйня с Ruby/Perl/etc. Лучше выбирать классический джентельменский набор - PHP + MySQL/Postgre + JS на фронте. А то напридумывают свои какие-то моднявые связки Go + TypeScript, а потом молодняк приходят на StackOverflow с каким-то вопросом и ждёт ответа по 6-7 часов от того несчастного мелкого комьюнити, которое образовалось в следствие саздания новага язига, каторый, сматрите, бистрее пыхыпы на 5%!. Фу блять.
современный PHP 7 в среднем в 2-3 раза быстрее Python:
https://benchmarksgame.alioth.debian.org/u64q/php.html
https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=php&lang2=hack
https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=php&lang2=yarv
(выше в тестах сложные алгоритмы, а на базовых операция -- циклы, динамические массивы, простые мат.операции PHP быстрее в 3 раза)
Ну как-то поймёшь, вопрос -- на каком уровне. Не попробуешь -- не узнаешь, опять же.
Проиграл с матёрого фронтендщика
Юзаю в конторе, всё нормально, подводных не обнаружено.
Я не столько хотел заострить внимание на производительности, сколько на объёме комьюнити. На PHP уже столько гайдов и мануалов, столько собак съедено, что в него достаточно просто войти имея желание, терпение и умение правильно формировать поисковые запросы в гугле. А они продолжают создавать Ruby, Go, Rust, Perl, etc тем самым разбивая комьюнити на меньшие группки.
у дж на ноде есть проблема ака каждую неделю учи новый фреймворк , алсо там нормальное ООП ещё не подвезли даже с ES6
я думаю ты же понимаешь в чём разница работы ужа и пыхи ?
Ruby вышел в том же году что и php , но как не странно на борту у него уже тогда был бест практис , что и стало даже + ибо не было тонны говнокода
Go мимо ибо он убийца С\С++ потому ниша в вебе у него не велика
Rust туда же к GO
Perl - старый пережиток был ранее PHP
Руби (точнее популярный фреймворк Руби он Рейлс) за образец точно брать не стоит, там были приняты такие вещи, как патчинг одним модулем другого: https://habrahabr.ru/company/Voximplant/blog/269467/
Ну и вообще там много неоднозначного, везде статические вызовы, в тех же моделях замешаны active record, валидация, генерация ссылок.
>>1033029
В создании новых языков нет ничего плохого - потому что часто старые языки (PHP) нельзя так просто переделать из-за проблем совместимости.
Но тут конечно важно учитывать, что в тот же PHP вложено огромное количество сил, и в сам язык, и в оптимизации, и в фреймворки, библиотеки. Переходя на новый язык, мы от всего этого отказываемся.
>>1032928
Удаление делается по ключу. Вообще, ключи в массиве сделаны специально, чтобы искать по ним элементы.
> for($z = 0; $z <= count($bills); $z++) {
> if($bills[$z] == 0){
Ты в цикле ищешь элементы с ключами 0, 1, 2 ..., а у тебя в массиве таких ключей нет. Для перебора массива лучше использовать foreach, а не for.
>>1032910
Ключ элемента массива указан слева, значение элемента справа.
Посмотри мануал по функции pg_query: http://php.net/manual/ru/function.pg-query.php
> Возвращаемые значения
> Ресурс результата запроса в случае успеха или FALSE в случае возникновения ошибки
Она возвращает ресурс - специальный идентификатор, который обозначает результат запроса и из которого можно получить этот результат с помощью другой функции вроде pg_fetch_row (я не особо разбираюсь в pg-функциях).
Я советую почитать про то, как пользоваться pg-функциями, начать можно отсюда: http://php.net/manual/ru/pgsql.examples-basic.php
Вот инфа про ресурсы, если надо: http://php.net/manual/ru/language.types.resource.php
Также, у тебя в коде SQL инъекция, нельзя вставлять данные прямо в запрос: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
>>1032731
Потому что неправильно написано. Давай на это посмотрим:
[+7] - это обозначает "ровно один символ из набора '+' или '7'". Перечитай, что обозначают разные виды скобок. Квадратные скобки обозначают "один любой из указанных символов".
>>1032730
> foreach ($quest->workers->w as $w->endStavka = $value)
так писать нельзя, справа от as нужно указать одну или две переменных, а не выражение. Перечитай пожалуйста про цикл foreach: http://php.net/manual/ru/control-structures.foreach.php
И тогда наверно ошибка исчезнет.
Также, я уже видел предыдущую версию этого кода и где-то выше написал по ней замечания, я вижу что те же проблемы остаются и в этой версии кода.
>>1032729
А ты попробуй написать такое выражение:
- цифра, за ней любой из символов \s ( ) -, повторяющийся любое число раз
После чего возьми его в скобки и укажи, что оно повторяется ровно 10 раз.
Посмотри мануал по функции pg_query: http://php.net/manual/ru/function.pg-query.php
> Возвращаемые значения
> Ресурс результата запроса в случае успеха или FALSE в случае возникновения ошибки
Она возвращает ресурс - специальный идентификатор, который обозначает результат запроса и из которого можно получить этот результат с помощью другой функции вроде pg_fetch_row (я не особо разбираюсь в pg-функциях).
Я советую почитать про то, как пользоваться pg-функциями, начать можно отсюда: http://php.net/manual/ru/pgsql.examples-basic.php
Вот инфа про ресурсы, если надо: http://php.net/manual/ru/language.types.resource.php
Также, у тебя в коде SQL инъекция, нельзя вставлять данные прямо в запрос: https://github.com/codedokode/pasta/blob/master/security/sql-injection.md
>>1032731
Потому что неправильно написано. Давай на это посмотрим:
[+7] - это обозначает "ровно один символ из набора '+' или '7'". Перечитай, что обозначают разные виды скобок. Квадратные скобки обозначают "один любой из указанных символов".
>>1032730
> foreach ($quest->workers->w as $w->endStavka = $value)
так писать нельзя, справа от as нужно указать одну или две переменных, а не выражение. Перечитай пожалуйста про цикл foreach: http://php.net/manual/ru/control-structures.foreach.php
И тогда наверно ошибка исчезнет.
Также, я уже видел предыдущую версию этого кода и где-то выше написал по ней замечания, я вижу что те же проблемы остаются и в этой версии кода.
>>1032729
А ты попробуй написать такое выражение:
- цифра, за ней любой из символов \s ( ) -, повторяющийся любое число раз
После чего возьми его в скобки и укажи, что оно повторяется ровно 10 раз.
> Имя кошки - http://ideone.com/9gYMJD
Верно
> Лев Толстой: http://ideone.com/c7jA9P
Верно, но слишком длинные конструкции вроде $word1[array_rand($word1)] лучше было бы не писать прямо в строке, а вынести в отдельную переменную.
> Палиндром: http://ideone.com/k76YfM
Ок, верно
>>1032449
Справедливости ради, лучше было бы сначала разобраться, какие сервер выставляет заголовки. Если это хостинг, то вполне возможно, что там выставлены принудительно заголовки, вызывающие кеширование статических файлов на какое-то время.
Версию руками лучше не менять, а автоматизировать этот процесс. Ну или просто отключить выставление этих заголовков на сервере, которые включают кеширование без проверки актуальности.
>>1032333
Ну вот получается, что в итоге проблема просто в том, что разные люди по-разному называют вещи.
>>1032306
После 700-900 постов
Если не смог решить проблему, дай минимальный пример кода и напиши, какую ошибку он выдает.
>>1032222
Заголовки отдавать - это дело контроллера в MVC.
>>1032041
У быстрого компилируемого языка свои проблемы - хуже диагностика ошибок (многие ошибки сразу не обнаруживаются, другие валят процесс в сегфолт, иногда без нормального стектрейса), нельзя так просто отлаживать, нужно знать С++ чтобы смотреть исходники.
Ну и вопрос еще, сколько ты процентов времени сэкономишь, перенеся класс Request в C++. Может быть, большая часть времени не в нем теряется.
>>1032002
Сервер может выдавать заголовки, управляющие кешированием, советую для начала про них почитать и посмотреть, что в твоем случае указано:
https://developer.mozilla.org/ru/docs/Web/HTTP/Кэширование
Ну а также научиться чистить кеш в браузере.
>>1031692
- для хранения списка чего-либо, каких-то значений или сущностей
- для задания соответствия между одними значениями и другими (код ошибки -> текст ошибки, фамилия ученика -> оценка по математике)
Если не смог решить проблему, дай минимальный пример кода и напиши, какую ошибку он выдает.
>>1032222
Заголовки отдавать - это дело контроллера в MVC.
>>1032041
У быстрого компилируемого языка свои проблемы - хуже диагностика ошибок (многие ошибки сразу не обнаруживаются, другие валят процесс в сегфолт, иногда без нормального стектрейса), нельзя так просто отлаживать, нужно знать С++ чтобы смотреть исходники.
Ну и вопрос еще, сколько ты процентов времени сэкономишь, перенеся класс Request в C++. Может быть, большая часть времени не в нем теряется.
>>1032002
Сервер может выдавать заголовки, управляющие кешированием, советую для начала про них почитать и посмотреть, что в твоем случае указано:
https://developer.mozilla.org/ru/docs/Web/HTTP/Кэширование
Ну а также научиться чистить кеш в браузере.
>>1031692
- для хранения списка чего-либо, каких-то значений или сущностей
- для задания соответствия между одними значениями и другими (код ошибки -> текст ошибки, фамилия ученика -> оценка по математике)
Не хочешь заняться переводом? Английский подучишь, материал запомнишь и заодно другим людям поможешь.
>>1031533
Сколько угодно, но надо помнить, что данные сессии хранятся на диске, загружаются в память в начале скрипта и выгружаются в конце. Соответственно, это будет создавать дисковый трафик, и при большом числе посещений это может замедлить работу сервера, так как скорость чтения/записи ограничена.
>>1031384
Для тестов обычно используют временную БД в памяти, а ты наверно указал параметры доступа к обычной БД.
>>1031410
А эти строчки влияют на выбор БД Ларавелем? И не переопределяются ли параметры где-то в коде?
>>1031490
начинающим вместо сборок стоило бы сначала научиться использовать встроенный PHP-сервер, настраивать Апач или нгинкс. Которые и используются в сборках.
>>1031474
Что-то по набору программ это ZverCD напоминает, он случайно винду не заменяет при установке?
Я бы побоялся себе столько программ сразу ставить. Тем более что многие из них закрытые и неизвестно что делают.
Не хочешь заняться переводом? Английский подучишь, материал запомнишь и заодно другим людям поможешь.
>>1031533
Сколько угодно, но надо помнить, что данные сессии хранятся на диске, загружаются в память в начале скрипта и выгружаются в конце. Соответственно, это будет создавать дисковый трафик, и при большом числе посещений это может замедлить работу сервера, так как скорость чтения/записи ограничена.
>>1031384
Для тестов обычно используют временную БД в памяти, а ты наверно указал параметры доступа к обычной БД.
>>1031410
А эти строчки влияют на выбор БД Ларавелем? И не переопределяются ли параметры где-то в коде?
>>1031490
начинающим вместо сборок стоило бы сначала научиться использовать встроенный PHP-сервер, настраивать Апач или нгинкс. Которые и используются в сборках.
>>1031474
Что-то по набору программ это ZverCD напоминает, он случайно винду не заменяет при установке?
Я бы побоялся себе столько программ сразу ставить. Тем более что многие из них закрытые и неизвестно что делают.
Для начала, можешь ли ты запустить встроенный в PHP сервер без PhpStorm (из командной строки)? работает ли он?
Если да, то правильно ли в настройках PHPStorm указан путь к интерпретатору PHP?
Какая версия PHP?
>>1031432
Если человек не может встроенный сервер запустить, ему лучше научиться это делать, а потом браться за сборки.
>>1031179
Просить советов, потом просить дополнительную усложненную задачу по той же теме.
>>1031122
Открыть отладчик (Ctrl + Shift + I), посмотреть свойства, примененные к диву, его размеры.
Если не очень знаешь CSS, и есть время, то советую задачи на HTML/CSS из шапки.
>>1030925
Знак = добавляет новый элемент массива, массив постоянно растет и цикл никогда не закончится. тут правильнее использовать == вместо = и foreach вместо for.
>>1030872
В PhpStorm нет встроенного сервера, он лишь умеет запускать встроенный в PHP сервер. Да, подойдет.
Для начала, можешь ли ты запустить встроенный в PHP сервер без PhpStorm (из командной строки)? работает ли он?
Если да, то правильно ли в настройках PHPStorm указан путь к интерпретатору PHP?
Какая версия PHP?
>>1031432
Если человек не может встроенный сервер запустить, ему лучше научиться это делать, а потом браться за сборки.
>>1031179
Просить советов, потом просить дополнительную усложненную задачу по той же теме.
>>1031122
Открыть отладчик (Ctrl + Shift + I), посмотреть свойства, примененные к диву, его размеры.
Если не очень знаешь CSS, и есть время, то советую задачи на HTML/CSS из шапки.
>>1030925
Знак = добавляет новый элемент массива, массив постоянно растет и цикл никогда не закончится. тут правильнее использовать == вместо = и foreach вместо for.
>>1030872
В PhpStorm нет встроенного сервера, он лишь умеет запускать встроенный в PHP сервер. Да, подойдет.
Ты пропускаешь основы и берешься сразу за сложное. Прежде чем использовать Докер, нужно изучить хотя бы основы командной строки и основы линукса, а также изучить описание используемого образа, где там хранятся файлы, конфиги, как что менять.
Образы Докера обычно используют файловые системы только для чтения внутри контейнера и файлы внутрь "заливать" не надо, обычно там в контейнер монтируется папка с хоста.
>>1030803
Если изучить сначала ООП, а потом почитать мое описание паттернов работы с БД, то, наверно, не убегут.
>>1030787
Все твои проблемы из-за того, что ты пропускаешь изучение базовых вещей и берешься сразу за сложное.
Чтобы пользоваться Homestead (образом для виртуальной машины) нужно разумеется знать основы командной строки, основные команды линукса, администрирование сервера на линуксе, наверно немного прочесть про сам Вагрант, а также изучить документацию по образу: https://laravel.com/docs/5.4/homestead#introduction
Прочел ли ты эту документацию?
Что касается файлов, там предлагается расшарить папку с хоста в виртуальную машину. Хотя, можно и копировать файлы в виртуальную машину через scp, sftp или другие протоколы. Опять же, из-за того что ты не изучал линукс и возможности расшаривания папок/копирования файлов, ты и путаешься.
Кроме виртуальной машины, в PHP можно использовать разные варианты серверов:
- встроенный в PHP веб-сервер
- Апач + mod_php
- Нгинкс + php-fpm
Проще всего, конечно, встроенный в PHP веб-сервер. Для его использования надо знать лишь основы командной строки.
Но я не знаю, достаточно ли этого для ларавель? Что, если ему еще нужна база данных (ее надо установить и настроить), какие-то утилиты вроде композера или ноды? Их тоже надо установить, а также почитать хотя бы в общих чертах документацию по ним.
То есть если там упоминается композер, то желательно почитать хотя бы немного про него, если упоминается нода, то про нее и так далее.
Не спеши, изучи сначала более базовые вещи, а потом берись за сложные.
Я всегда готов помочь, если после чтения документации что-то осталось непонятно.
> Как мне подключиться к БД?
Через какой клиент? Где у тебя установлена БД и какая?
> Как использовать phpMyAdmin?
А ты его установил? Куда и как он настроен?
Ты пропускаешь основы и берешься сразу за сложное. Прежде чем использовать Докер, нужно изучить хотя бы основы командной строки и основы линукса, а также изучить описание используемого образа, где там хранятся файлы, конфиги, как что менять.
Образы Докера обычно используют файловые системы только для чтения внутри контейнера и файлы внутрь "заливать" не надо, обычно там в контейнер монтируется папка с хоста.
>>1030803
Если изучить сначала ООП, а потом почитать мое описание паттернов работы с БД, то, наверно, не убегут.
>>1030787
Все твои проблемы из-за того, что ты пропускаешь изучение базовых вещей и берешься сразу за сложное.
Чтобы пользоваться Homestead (образом для виртуальной машины) нужно разумеется знать основы командной строки, основные команды линукса, администрирование сервера на линуксе, наверно немного прочесть про сам Вагрант, а также изучить документацию по образу: https://laravel.com/docs/5.4/homestead#introduction
Прочел ли ты эту документацию?
Что касается файлов, там предлагается расшарить папку с хоста в виртуальную машину. Хотя, можно и копировать файлы в виртуальную машину через scp, sftp или другие протоколы. Опять же, из-за того что ты не изучал линукс и возможности расшаривания папок/копирования файлов, ты и путаешься.
Кроме виртуальной машины, в PHP можно использовать разные варианты серверов:
- встроенный в PHP веб-сервер
- Апач + mod_php
- Нгинкс + php-fpm
Проще всего, конечно, встроенный в PHP веб-сервер. Для его использования надо знать лишь основы командной строки.
Но я не знаю, достаточно ли этого для ларавель? Что, если ему еще нужна база данных (ее надо установить и настроить), какие-то утилиты вроде композера или ноды? Их тоже надо установить, а также почитать хотя бы в общих чертах документацию по ним.
То есть если там упоминается композер, то желательно почитать хотя бы немного про него, если упоминается нода, то про нее и так далее.
Не спеши, изучи сначала более базовые вещи, а потом берись за сложные.
Я всегда готов помочь, если после чтения документации что-то осталось непонятно.
> Как мне подключиться к БД?
Через какой клиент? Где у тебя установлена БД и какая?
> Как использовать phpMyAdmin?
А ты его установил? Куда и как он настроен?
Я подозреваю, что просто apt-get install для phpmyadmin может быть недостаточно, там еще может понадобиться что-то настроить, например, включить демон веб-сервера.
Ну и конечно нужно знать линукс, прежде чем его использовать.
>>1030806
> У меня есть проект, который я создал через composer. Но он никак не связан с тем, что в hosts
Я не очень понял, а что значит "не связан с тем, что в hosts"? hosts используется для добавления доменов без использования DNS-сервера. Там не пишутся названия проектов, а только доменные имена и соответсвующие им IP адреса.
Ты бы почитал хоть немного про то, что это за файл.
>>1030802
> Но я читал документацию с начала. Русскую. Там ребята начали с того, что хорошо было бы поставить homestead.
Чтобы им пользоваться, нужно изучить теорию сначала, линукс и его особенности, администрирование линукса, почитать документацию по самому homestead. Плохо, если документация об этом умолчала, это говорит о низком ее качестве.
> У меня не работает http://homestead.app
> Точнее, он как бы работает и пишет No input file specified.
Нужно смотреть логи веб-сервера либо php-fpm, в зависимости от того, как там это настроено (внутри виртуальной машины).
> Я хочу использовать MySQL, а там привык юзать phpMyAdmin. Хотел бы знать, как это использовать в связке с Laravel. Как установить, как начать пользоваться.
phpmyadmin устанавливается отдельно от лаправель, никак с ним не связан. Тебе надо его установить и настроить.
> Но как мне войти в свой проект-то?
Не понял что значит "войти в проект". Подсоединиться по SSH к виртуальной машине с веб-сервером? Или что?
Я подозреваю, что просто apt-get install для phpmyadmin может быть недостаточно, там еще может понадобиться что-то настроить, например, включить демон веб-сервера.
Ну и конечно нужно знать линукс, прежде чем его использовать.
>>1030806
> У меня есть проект, который я создал через composer. Но он никак не связан с тем, что в hosts
Я не очень понял, а что значит "не связан с тем, что в hosts"? hosts используется для добавления доменов без использования DNS-сервера. Там не пишутся названия проектов, а только доменные имена и соответсвующие им IP адреса.
Ты бы почитал хоть немного про то, что это за файл.
>>1030802
> Но я читал документацию с начала. Русскую. Там ребята начали с того, что хорошо было бы поставить homestead.
Чтобы им пользоваться, нужно изучить теорию сначала, линукс и его особенности, администрирование линукса, почитать документацию по самому homestead. Плохо, если документация об этом умолчала, это говорит о низком ее качестве.
> У меня не работает http://homestead.app
> Точнее, он как бы работает и пишет No input file specified.
Нужно смотреть логи веб-сервера либо php-fpm, в зависимости от того, как там это настроено (внутри виртуальной машины).
> Я хочу использовать MySQL, а там привык юзать phpMyAdmin. Хотел бы знать, как это использовать в связке с Laravel. Как установить, как начать пользоваться.
phpmyadmin устанавливается отдельно от лаправель, никак с ним не связан. Тебе надо его установить и настроить.
> Но как мне войти в свой проект-то?
Не понял что значит "войти в проект". Подсоединиться по SSH к виртуальной машине с веб-сервером? Или что?
В такой ситуации проще всего с помощью strace (под линукс) или procmon (винда) посмотреть, к каким файлам идет обращение при вызове gettext().
На винде в PHP5.4 у меня твой скрипт выдает:
> setlocale failed: locale function is not available on this platform....
Это и понятно, так как локали это линуксовая вещь и, хотя в винде есть их аналог, и PHP пытается его использовать, но называются сами локали там по-другому.
Например, у меня в винде var_dump(setlocale(LC_ALL, null)); выдает:
> string(26) "English_United States.1252"
В MSDN наверно можно найти, какие конкретно локали есть в винде.
Также, PHP5.3 не выдает ошибку, но сообщение не переводит. procmon не запускается и падает с ошибкой, потому посмотреть, куда он лезет, не могу.
На линуксе выдается ошибка в setlocale, из-за того, что у меня нет русской локали. Исправил локаль на "C", и увидел через strace, что код пытается лезть в /locale за сообщениями.
Просмотреть список доступных локалей в линуксе можно через locale -a, а текущую - набрав просто команду locale. В винде - в MSDN наверно.
Я вижу такие ссылки на MSDN:
- https://msdn.microsoft.com/en-us/library/x99tb11d.aspx
- https://msdn.microsoft.com/en-us/library/hzz3tw78.aspx
И вот тут интересная инфорамция на русском: https://anton-pribora.ru/articles/php/locales/
Видно, что в любом случае имена локалей не совпадают с линуксовыми.
В линуксе локали действительно называются вроде en_GB или en_GB.utf-8, но там есть подвох - гарантий, что та или иная локаль установлена в системе, нет, соответственно твое приложение рискует тоже не заработать (setlocale выдаст ошибку, если локаль не установлена в системе).
"локаль установлена в системе" - это значит, что где-то есть файлик(и), описывающие настройки для данной локали: формат чисел, дат, правила сортировки строк по алфавиту. В линуксе обычно локали устанавливаются системным менеджером пакетов.
В линуксе локаль задается через переменные окружения (обычно где-то в скрипте или конфиге, выполняемом при загрузке системы) и влияет на поведение программ и библиотек: на формат вывода чисел стандартными функциями (в PHP кстати тоже - при русской локали дробные числа выводятся с запятой вместо точки, что доставляет дополнительную боль), на сортировку строк стандартными функциями, а также на язык выводимых программами и библиотеками сообщений.
Переменные окружения хорошо подходят для задания локали по 2 причинам:
- они могут быть у каждой программы свои и можно одновременно работать с разными языками в нескольких консолях
- они наследуются от родителя при запуске дочернего процесса
Увы, тут есть и недостаток: переменные окружения общие для всех тредов многотредового процесса, то есть в случае с многопотоным PHP (например в mod_php) нельзя ставить независимо разные локали для разных потоков.
Локали влияют и на работу PHP, так как он использует библиотеки, которые смотрят на переменные окружения LC_.... и используют функции, зависящие от текущей локали. Локаль можно задавать через переменную LANG (общая настройка), LC_ALL или отдельно для каждой категории вроде LC_TIME.
То есть в Линуксе эти локали хорошо интегрированы, и разработчики программ ими пользуются. Что касается винды, надо читать доки по setlocale в MSDN.
Вернемся к gettext.
Если что, документация по сишной библиотеке gettext (а в PHP функции расширения gettext по сути просто вызывают эту библиотеку) есть тут: https://www.gnu.org/software/gettext/manual/gettext.html#gettext
Конкретно, вот документация по пути к файлам gettext: https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs
> Because many different languages for many different packages have to be stored we need some way to add these information to file message catalog files. The way usually used in Unix environments is have this encoding in the file name. This is also done here. The directory name given in bindtextdomains second argument (or the default directory), followed by the name of the locale, the locale category, and the domain name are concatenated:
> dir_name/locale/LC_category/domain_name.mo
> The default value for dir_name is system specific. For the GNU library, and for packages adhering to its conventions, it’s:
> /usr/local/share/locale
> locale is the name of the locale category which is designated by LC_category. For gettext and dgettext this LC_category is always LC_MESSAGES. The name of the locale category is determined through setlocale (LC_category, NULL). When using the function dcgettext, you can specify the locale category through the third argument.
То есть самый надежный способ, получается такой:
- ставить дефолтную локаль (чтобы все встроенные функции работали одинаково независимо от внешних настроек)
- задать язык с помощью выбора домена (например: myapp-ru)
- задать базовый путь для сообщений в bindtextdomain (например /x/y/z/messages/)
То есть переключать языки не с помощью локали, а выбором домена. Вообще, домен наверно был придуман для того, чтобы у приложения или группы приложений были свои независимые языковые файлы, но можно его использовать и для выбора языка.
Я проверил, локаль "C" работает и в линуксах, и в винде. Однако, при ее использовании gettext даже не пытается искать файл с сообщениям.
При выборе локали en_US.utf8 (только линукс, в винде не поддерживается), домена mydomain, папки /tmp, strace показывает, что gettext ищет файл переводов по следующим путям:
- /tmp/en_US/LC_MESSAGES/mydomain.mo
- /tmp/en/LC_MESSAGES/mydomain.mo
(так как в линуксе есть еще синонимы (алиасы) локалей и он их тоже перебирает).
То, что gettext не выводит никаких ошибок, это конечно, неудачное решение.
Также можно попробовать не использовать gettext, а например, стороннюю библиотеку Symfony Translator: https://symfony.com/doc/current/components/translation.html
Это примерно то же, но написано на PHP. Надо понимать, что в отличие от сишного расширения, которое умеет загружать данные один раз в память процесса при первом запуске скрипта, тут загрузка сообщений может работать медленнее (например чтение данных из mo-файла сделано на PHP и будет работать небыстро) и будет происходить при каждом выполнении скрипта. Однако, если использовать загрузку из PHP файлов, и opcache, то может быть, эти данные закешируются в shared memory и не будут грузиться при каждом запуске скрипта.
Стоит глянуть исходники этой библиотеки, чтобы лучше понять, как она работает. Она вроде умеет конвертировать сообщения в формат php-файлов.
Если ты встроил веб-сервер в процесс PHP и не умираешь после каждого запроса, то медленная загрузка не так критична.
Для форматирования строк (вставки чисел, подстрок, изменния формы слов в зависимости от числа или пола) стоит использовать возможности MessageFormatter в расширении Intl. То, что есть в gettext (ngettext) и в Symfony (transChoice) - это пародия на нормальный форматтер сообщений.
Я, признаюсь, сколько-то лет назад не знал про Intl и изобретал свои форматтеры со своим синтаксисом.
Также, я не уверен, что putenv на что-то влияет, так как она может быть только переопределяет переменные окружения внутри PHP для процессов-потомков и для getenv(), но не влияет на то, что прочитает библиотека gettext. Но я не уверен.
В такой ситуации проще всего с помощью strace (под линукс) или procmon (винда) посмотреть, к каким файлам идет обращение при вызове gettext().
На винде в PHP5.4 у меня твой скрипт выдает:
> setlocale failed: locale function is not available on this platform....
Это и понятно, так как локали это линуксовая вещь и, хотя в винде есть их аналог, и PHP пытается его использовать, но называются сами локали там по-другому.
Например, у меня в винде var_dump(setlocale(LC_ALL, null)); выдает:
> string(26) "English_United States.1252"
В MSDN наверно можно найти, какие конкретно локали есть в винде.
Также, PHP5.3 не выдает ошибку, но сообщение не переводит. procmon не запускается и падает с ошибкой, потому посмотреть, куда он лезет, не могу.
На линуксе выдается ошибка в setlocale, из-за того, что у меня нет русской локали. Исправил локаль на "C", и увидел через strace, что код пытается лезть в /locale за сообщениями.
Просмотреть список доступных локалей в линуксе можно через locale -a, а текущую - набрав просто команду locale. В винде - в MSDN наверно.
Я вижу такие ссылки на MSDN:
- https://msdn.microsoft.com/en-us/library/x99tb11d.aspx
- https://msdn.microsoft.com/en-us/library/hzz3tw78.aspx
И вот тут интересная инфорамция на русском: https://anton-pribora.ru/articles/php/locales/
Видно, что в любом случае имена локалей не совпадают с линуксовыми.
В линуксе локали действительно называются вроде en_GB или en_GB.utf-8, но там есть подвох - гарантий, что та или иная локаль установлена в системе, нет, соответственно твое приложение рискует тоже не заработать (setlocale выдаст ошибку, если локаль не установлена в системе).
"локаль установлена в системе" - это значит, что где-то есть файлик(и), описывающие настройки для данной локали: формат чисел, дат, правила сортировки строк по алфавиту. В линуксе обычно локали устанавливаются системным менеджером пакетов.
В линуксе локаль задается через переменные окружения (обычно где-то в скрипте или конфиге, выполняемом при загрузке системы) и влияет на поведение программ и библиотек: на формат вывода чисел стандартными функциями (в PHP кстати тоже - при русской локали дробные числа выводятся с запятой вместо точки, что доставляет дополнительную боль), на сортировку строк стандартными функциями, а также на язык выводимых программами и библиотеками сообщений.
Переменные окружения хорошо подходят для задания локали по 2 причинам:
- они могут быть у каждой программы свои и можно одновременно работать с разными языками в нескольких консолях
- они наследуются от родителя при запуске дочернего процесса
Увы, тут есть и недостаток: переменные окружения общие для всех тредов многотредового процесса, то есть в случае с многопотоным PHP (например в mod_php) нельзя ставить независимо разные локали для разных потоков.
Локали влияют и на работу PHP, так как он использует библиотеки, которые смотрят на переменные окружения LC_.... и используют функции, зависящие от текущей локали. Локаль можно задавать через переменную LANG (общая настройка), LC_ALL или отдельно для каждой категории вроде LC_TIME.
То есть в Линуксе эти локали хорошо интегрированы, и разработчики программ ими пользуются. Что касается винды, надо читать доки по setlocale в MSDN.
Вернемся к gettext.
Если что, документация по сишной библиотеке gettext (а в PHP функции расширения gettext по сути просто вызывают эту библиотеку) есть тут: https://www.gnu.org/software/gettext/manual/gettext.html#gettext
Конкретно, вот документация по пути к файлам gettext: https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs
> Because many different languages for many different packages have to be stored we need some way to add these information to file message catalog files. The way usually used in Unix environments is have this encoding in the file name. This is also done here. The directory name given in bindtextdomains second argument (or the default directory), followed by the name of the locale, the locale category, and the domain name are concatenated:
> dir_name/locale/LC_category/domain_name.mo
> The default value for dir_name is system specific. For the GNU library, and for packages adhering to its conventions, it’s:
> /usr/local/share/locale
> locale is the name of the locale category which is designated by LC_category. For gettext and dgettext this LC_category is always LC_MESSAGES. The name of the locale category is determined through setlocale (LC_category, NULL). When using the function dcgettext, you can specify the locale category through the third argument.
То есть самый надежный способ, получается такой:
- ставить дефолтную локаль (чтобы все встроенные функции работали одинаково независимо от внешних настроек)
- задать язык с помощью выбора домена (например: myapp-ru)
- задать базовый путь для сообщений в bindtextdomain (например /x/y/z/messages/)
То есть переключать языки не с помощью локали, а выбором домена. Вообще, домен наверно был придуман для того, чтобы у приложения или группы приложений были свои независимые языковые файлы, но можно его использовать и для выбора языка.
Я проверил, локаль "C" работает и в линуксах, и в винде. Однако, при ее использовании gettext даже не пытается искать файл с сообщениям.
При выборе локали en_US.utf8 (только линукс, в винде не поддерживается), домена mydomain, папки /tmp, strace показывает, что gettext ищет файл переводов по следующим путям:
- /tmp/en_US/LC_MESSAGES/mydomain.mo
- /tmp/en/LC_MESSAGES/mydomain.mo
(так как в линуксе есть еще синонимы (алиасы) локалей и он их тоже перебирает).
То, что gettext не выводит никаких ошибок, это конечно, неудачное решение.
Также можно попробовать не использовать gettext, а например, стороннюю библиотеку Symfony Translator: https://symfony.com/doc/current/components/translation.html
Это примерно то же, но написано на PHP. Надо понимать, что в отличие от сишного расширения, которое умеет загружать данные один раз в память процесса при первом запуске скрипта, тут загрузка сообщений может работать медленнее (например чтение данных из mo-файла сделано на PHP и будет работать небыстро) и будет происходить при каждом выполнении скрипта. Однако, если использовать загрузку из PHP файлов, и opcache, то может быть, эти данные закешируются в shared memory и не будут грузиться при каждом запуске скрипта.
Стоит глянуть исходники этой библиотеки, чтобы лучше понять, как она работает. Она вроде умеет конвертировать сообщения в формат php-файлов.
Если ты встроил веб-сервер в процесс PHP и не умираешь после каждого запроса, то медленная загрузка не так критична.
Для форматирования строк (вставки чисел, подстрок, изменния формы слов в зависимости от числа или пола) стоит использовать возможности MessageFormatter в расширении Intl. То, что есть в gettext (ngettext) и в Symfony (transChoice) - это пародия на нормальный форматтер сообщений.
Я, признаюсь, сколько-то лет назад не знал про Intl и изобретал свои форматтеры со своим синтаксисом.
Также, я не уверен, что putenv на что-то влияет, так как она может быть только переопределяет переменные окружения внутри PHP для процессов-потомков и для getenv(), но не влияет на то, что прочитает библиотека gettext. Но я не уверен.
В документации xgettext нет параметра, описывающего метку, по которой надо искать строки?
Также, xgettext рассчитан на Си-подобный синтаксис, но может ошибиться, в теории хорошо бы написать свой скрипт разбора PHP кода на токены и выцеживания оттуда строк с переводами.
>>1030104
Функция getEndStavka вызывается когда значение поля $this->rang еще не задано.
Потому надо сначала его задать (в конструкторе), а только потом вызывать. Ну и я выше писал, что поле endStavka делать вообще плохая идея.
по описанию какая-то шарашкина контора, в нормальных компаниях с заказчиком общаются менеджер+тимлид(коим я являюсь), никто в никого говном не кидается(такие заказчики были, но уже как пару лет шлём таких нахуй при первом признаке аутиста).
по процессу работы, ничего не отваливается само и просто так. юзать ебучие цмс без которые постоянно обновляются без обратной поддержки апи, чтобы ничего не отваливалось советую прочитать про continuous integration
>Фишка в том, что наши программисты гуглеры, а не ученые. Это обычно молодые, только выпустившиеся пацаны, которые возможно выучили Java, возможно даже C/C++ и может быть Python. Они не в состоянии понимать пробздетый язык, но мы все равно хотим, чтобы они делали хороший софт. Таким образом, мы даем им легкопонимаемый язык, к которому они быстро привыкнут.
и чем это отменяет что он легче чем кресты но сохраняет их профит ?
Я сильно сомневаюсь в том, что там написано, про корпорации. По моим ощущениям, Го сделан на замену Си, а не Си++ (он отличается от Си в первую очередь добавлением ООП, классов, нейсмпейсов, исключений).
Соответственно, Го придуман для написания небольших утилит, а также многопоточных сетевых демонов (ну то есть программ, которые принимают какие-то сообщения по сети, что-то с ними делают и отправляют на них ответ).
Насчет больших приложений (убийца Явы и PHP конечно) - тут я не уверен, там пока банально дженериков нет, то есть вы например не можете объявить тип "Коллекция объектов класса Пользователь". Исключений нет, ООП есть, но немного странный. Я писал небольшую утилиту на Го ( https://github.com/codedokode/guarddog ) но напрочь позабыл, что там неудобно.
А, вспомнил, одна из неудачных имхо фич - это разделение функций на public/private по регистру первой буквы метода. Сильно портит код, имхо.
> Посудите: можно нанять 100 посредственных программистов, дать им в руки Go и эта армия обезьян будет генерить вам много «неплохого» и очень даже поддерживаемого кода!
Только чтобы писать на Го, надо сначала изучить Си. Не знаю, хороший ли это выбор для начинающего. Иначе код будет очень плохой. Ну например, разработчик должен понимать разницу (в том числе в плане производительсности) между передачей структур по ссылке и по значению.
Там много низкоуровневых моментов, без знания Си будет тяжко.
Нет ничего лучше Си и С++ в совокупности. Двачую бро.
Можно нубский вопрос, елси С++ так шикарно работает, производительность - Великая и т.д Почему на нем пишут мало корпорации и игроделов? На нем же можно отлично оптимизироваться.
Если выучишь Си - С легкостью выучишь и С++, зачем тратить время на Го, когда ты уже считай профи?
Го можно выучить отвлеченно и зная задачи которые он выполняет, ну типа как если ты выучил пару языков и чтобы увеличить свои критерии выучиваешь остальные языки для гибкости. Страуструп рекомендует знать как минимум 5 языков фундаментально.
Нас потрут за оффтоп
Потому что он рассчитан на высокую скорость выполнения кода, но отнюдь не на высокую скорость написания (да и компиляции тоже, если честно).
Например, там нет сборщика мусора, что замедляет написание и отладку кода, программист вынужден думать о времени жизни переменной вместо написания самой программы. Банальная задача - вернуть строку из функции - уже приводит к размышлениям, какой тип объектов-ссылок использовать.
Также, у него высокий порог вхождения, нужно многое изучить, чтобы на нем писать.
Ну и много неудобных оставшихся по наследству вещей:
- нет модулей
- макросы
- нет проверки границ массивов
- заголовочные файлы
Потому когда хотят написать простой сайт, на PHP это будет сделать гораздо быстрее и потребует менее опытных разработчиков.
Есть массив, внутри массива каждый ключ содержит значение в виде массива.
Требуется отсортировать массив так, что если больше n-значений в массиве, то добавляем в другой массив ключ-значение подходящего.
<a href="2.php?name=1">LINK</a>
Во втором написано:
$name;
echo $name;
Пишет: Undefined variable: name. Как я понял, он значение не передает. Вопрос: почему?
Благодарю.
уже не надо. сам додумался:
foreach ($foo as $key => $value) {
if (count($value) >= n ) {
$bar[$key] = $value;
}
}
Что гуглить, мань, если у меня документация по ларавелю по умолчанию открыта на элоквенте? Я умею в зависимости one2one, one2many и тд. Я задал вопрос по архитектуре, логике, а не синтаксису.
а что по логике ? на каждую таблицу делаешь по модели , конектишь их через отношения , там где нужно взять что то зависимое делаешь $model->find(10)->sense(); и получаешь тот же массив всех связанных ? Какая ещё тебе архитектура нужна поверх MVC ?
По тому как ты задал вопрос , твои классы = моделям , связать через отношения , и будешь получать свой обьект с значениями колонок
>>1033454
Может я и правда плохо сформулировал вопрос, прошу прощения, попробую переформулировать.
В самом конце я бы хотел иметь объект (или массив объектов), например user с полями id:int, firstName:string, secondName:string, rentedBooks:object[]. Здесь первые три поля из таблички юзеров, а арендованные книжки из таблички книжек. Хочу обращаться потом к объекту user->rentedBooks[7], например, ну вы поняли.
В обычном пхп я бы создал класс User и класс Book, а потом вытаскивал данные и создавал бы инстансы этих классов. Но как это сделать в ларавеле? Где прописывать запросы к БД и создавать инстансы?
$query = "SELECT data FROM searches WHERE id = $id";
$result = pg_query($query) or die('Query failed: ' . pg_last_error());
Если ID существует, то выводится JSON-массив, записанный мною ранее под этим ID. Если ID нет, то на фронте тригерится .fail().
Чо делать?
по классике MVC вся работа с бизнес логикой должна быть в моделе , выходи так ты делаешь модель User делаешь отношение что у 1 User может быть много книг (я думаю с этим ты разобрался) , так как книга арендованная (видно так) то в модели Book ты ставишь что у книги может быть 1 User , в контроллере ты создаёшь инстанс пользователя , находишь пользователя по id например и через эти отношения получаешь массив объектов Book вот пример кода
$user->book();
Нет, а что?
Сказано, что если заключить регулярное выражение между % и $, то оно будет искать только фразу в регулярном выражении и не будет искать фразу, где есть лишние символы(ну например не найдет "кот" в слове "скотина", как написал ОП-доброкун, нувыпонели).
Если я пишу вот так:
$regexp = '/^[(+7)|8][0-9]{4}$/u';
то почему-то цифры, начинающиеся на +7, не соответствуют регулярному выражению.
Если пишу без шапочки и доллара, то все норм, цифры начинающиеся на +7 валидность проходят, и на 8 тоже.
Любопытно было посмотреть. Вообще, это наверно первый раз, когда я смотрю видео на этом сайте (твитче), немного непривычно, что там постоянно куда-то все переключается, открываются какие-то окна, иногда открывается сама же страница стрима, ну наверно стримы так и выглядят, я не знаю.
Интересно конечно посмотреть, как учебник воспринимают другие люди. Я старюсь вычитывать уроки, представляя себя ничего не знающим и не умеющим новичком, но какие-то вещи все равно можно понять только из подобных стримов. Вот заметил, например, что неудобно набирать код задачи про кубики и что часто происходят опечатки - видимо, надо еще несколько раз напомнить, что надо ставить везде точку с запятой. Ну и про проценты может стоит добавить пояснения, хотя разве их не изучают в средней школе? Я помню, мы что-то такое изучали.
Также, немного неудобно, что там у автора высокое разрешение и мелкие буквы и даже в 720p символы вроде "равно" плохо видны. Я бы советовал, если это нетрудно, увеличивать шрифт в редакторе, да и в браузере, раза в полтора-два.
Не знаю, может быть еще стоило написать названия использованных программ, чтобы те, кто заинтересовался, могли бы их себе установить тоже.
Ну и конечно на первой задаче обычной сложности (про кредит), в отличие от предыдущих, которые скорее служат для повышения уверенности в себе, стрим закончился. Ну ладно, пусть аноны сами немного голову поломают, не все же готовые решения смотреть.
---
Ну и еще, может автор не знает, но можно заставить браузер отображать текст со всеми пробелами и переводами строк:
---
Чтобы переносы строк нормально работали и в браузере и в ideone (и в консоли), можно использовать для этого \n, а в начале программы поставить
header("Content-Type: text/plain; charset=utf-8");
Это заставит браузер воспринимать то, что выводит твоя программа, как обычный текст, а не HTML, и уважать переносы строк в нем (так как в языке HTML перенос строки равносилен пробелу).
Иначе перенос строки будет в исходном коде страницы (его можно увидеть нажав Ctrl + U), но на самой странице его не будет.
---
Также, оператора из 2 звездочек нет, для возведения в степень (в том числе дробную, возведение в 1/3 = корень третьей степени и отрицательную, x ^ -3 = 1 / (x ^ 3)) есть функция pow() , но по моему она не умеет возводить в степень отрицательные числа.
Любопытно было посмотреть. Вообще, это наверно первый раз, когда я смотрю видео на этом сайте (твитче), немного непривычно, что там постоянно куда-то все переключается, открываются какие-то окна, иногда открывается сама же страница стрима, ну наверно стримы так и выглядят, я не знаю.
Интересно конечно посмотреть, как учебник воспринимают другие люди. Я старюсь вычитывать уроки, представляя себя ничего не знающим и не умеющим новичком, но какие-то вещи все равно можно понять только из подобных стримов. Вот заметил, например, что неудобно набирать код задачи про кубики и что часто происходят опечатки - видимо, надо еще несколько раз напомнить, что надо ставить везде точку с запятой. Ну и про проценты может стоит добавить пояснения, хотя разве их не изучают в средней школе? Я помню, мы что-то такое изучали.
Также, немного неудобно, что там у автора высокое разрешение и мелкие буквы и даже в 720p символы вроде "равно" плохо видны. Я бы советовал, если это нетрудно, увеличивать шрифт в редакторе, да и в браузере, раза в полтора-два.
Не знаю, может быть еще стоило написать названия использованных программ, чтобы те, кто заинтересовался, могли бы их себе установить тоже.
Ну и конечно на первой задаче обычной сложности (про кредит), в отличие от предыдущих, которые скорее служат для повышения уверенности в себе, стрим закончился. Ну ладно, пусть аноны сами немного голову поломают, не все же готовые решения смотреть.
---
Ну и еще, может автор не знает, но можно заставить браузер отображать текст со всеми пробелами и переводами строк:
---
Чтобы переносы строк нормально работали и в браузере и в ideone (и в консоли), можно использовать для этого \n, а в начале программы поставить
header("Content-Type: text/plain; charset=utf-8");
Это заставит браузер воспринимать то, что выводит твоя программа, как обычный текст, а не HTML, и уважать переносы строк в нем (так как в языке HTML перенос строки равносилен пробелу).
Иначе перенос строки будет в исходном коде страницы (его можно увидеть нажав Ctrl + U), но на самой странице его не будет.
---
Также, оператора из 2 звездочек нет, для возведения в степень (в том числе дробную, возведение в 1/3 = корень третьей степени и отрицательную, x ^ -3 = 1 / (x ^ 3)) есть функция pow() , но по моему она не умеет возводить в степень отрицательные числа.
Не так. Не %, а ^.
^ обозначает "в этом месте должно быть начало строки". То есть ^abc ищет abc только если эти буквы идут в самом начале строки.
Очевидно что ^ можно ставить только перед остальными символами, иначе он теряет специальное значение и обозначает просто каретку.
Внутри квадратных скобок ^ имеет другой смысл и значит "любой символ, кроме указанных".
$ обозначает "здесь должен быть конец строки", и abc$ найдет abc только если они идут в самом конце строки.
По твоей регулярке, ты не понял, как работают квадратные скобки. Они значат "один любой из указанных символов". Соответственно [(+7)|8] значит "один любой символ из набора: круглые скобки, плюс, семерка, вертикальная черта. восьмерка". Внутри квадратных скобок почти все символы, кроме ^ - \ ] не имеют специального значения и обозначают сами себя.
Мануал http://php.net/manual/ru/regexp.reference.character-classes.php
>цифры начинающиеся на +7 валидность проходят, и на 8 тоже
забыл сказать: но валидность проходят и наборы символов, где в начале и в конце стоят другие символы.
>Соответственно [(+7)|8] значит "один любой символ из набора: круглые скобки, плюс, семерка, вертикальная черта. восьмерка"
А если экранировать круглые скобки, то будет искаться либо +7, либо 8?
Экранирование лишает символ специального смысла. Например, + значит повторение, а \+ просто символ "плюс".
Соответственно экранирование ничего не даст. Квадратные скобки обозначают "один из указанных символов" и внутри них строить какие-то конструкции нельзя.
Ну вроде понял, спасибо большое.
Спасибо за замечание, в следующей трансляции постараюсь исправить.
Реально, на хекслете и за 40+ учатся мужики, а потом устраиваются джунами и устраивают карьеру погромиста.
Спасибо за инфу. Да Си тугой язык, я вечерами ломал голову чтобы обыкновенный цикл сделать. Даже не думал что это так глобально.
> Также, оператора из 2 звездочек нет, для возведения ...
https://3v4l.org/u4Gnp
>>1033733
Оно-то реально, но подумай как ты себя в коллективе чувствовать будешь, насколько комфортно будет другим учить великовозрастного дядю. У нас есть тимлиды в 25-27 лет с 7+ годами коммерческого опыта, джунов обычно набирают молодыми.
>>1033749
> 40+ мужики
> джунами
Мне было бы некомфортно с таким джуном общаться, сильный возрастной разрыв, как я буду учить такого человека, если он почти в 2 раза старше меня?
> при условии, что я шарю и предоставлю пруфы
"Болтовня ничего не стоит. Покажите мне код" как говорил Торвальдс.
>>1033565
Никогда больше не перекатывай треды, лентяй. Шапку на pastebin никто читать не будет + ты забыл про этот >>1019303 пост.
Щас буду практиковать верстку. Когда можно будет начать ПХП?
Спасибо, добра.
Просмотрел.
1000+ страниц и ни одного приличного листинга с кодом. В основном это краткий пересказ мануала, который ничему не учит.
Можно купить на рутрекере и листать иногда на предмет незнакомых слов если гугль отключили, денег за такое платить конечно не нужно.
TaM 6ykBbI "JI", HaIIPuMeP, HeT.
Я просто дописал некоторые буквы, которые захотел, например.
Там, мне кажется, все равно ничего более сложного и не придумаешь. Иди лучше дальше.
Скажем, есть чел, который не получил образования в сфере IT, учился там на какого-нибудь юриста, но знал php, вертску, js, mysql, вот это все, и фрилансом выполнил овер9000 заказов. Он будет считаться джуниором, если он пойдет на постоянную работу, где его деятельность не будет отличаться от той, когда он фрилансил? Почему?
Ты задачи Студенты и Файлообменник делал?
Если нет, то делай студентов, ОП написал к ней кучу статей.
По книгам: классика жанра Мэтт Зандстра "Объекты, Шаблоны и Методики Программирования". Потом думаю Фаулер.
У него нет опыта командной разработки.
Его код с большой долей вероятности, будет "попахивать", т.к. нет постоянного контроля качества.
Конечно зависит от конторы и реального уровня фрилансера. Понятно, что между 3 у.е час крудошлепом и 30 у.е. час лара/симфони ангуляр/реакт специалистом довольно чувствительная разница.
Может быть этот человек привык писать процедурную лапшу, а в компании используют ООП фреймворк вроде Симфони и его код не произведет впечатления. С другой стороны, может в компании тоже пишут процедурную лапшу, и тогда он хорошо впишется.
1. пишешь туда ссылку ssilka.com
2. генерирует рандом 4 символа и записывает в бд ссылку\символы asdf
3. апачь редиректет 404 запросы на страницу с пхп кодом stranica.com/asdf -> stranica.com/phpscript
4. смотрит _$SERVER[HTTP_REQUEST] = asdf и из бд вытаскивает ssilka.com
5. выводит на страницу жс скрипт с редиректом на ssilka.com
Как это сделать без редиректа на stranica.com/phpscript, через htaccess?
И что вообще еще можно поменять?
Спасибо, но не надо. Суть шапки в том, чтобы в начале треда была полезная информация и ссылки, а ты предлагаешь усложнить пользователям жизнь и переходить куда-то на гитхаб.
Также, ты не обратил внимание, но шапка играет еще важную роль. Там часть шапкии отображается на странице раздела, и в эту часть помещены важные вещи:
- что это за тред и чем в нем занимаются
- просьба не флудить
- то, что не требуется ничего устанавливать (чтобы не отпугнуть новичков)
- то, что не требуется специальных знаний и образования
Шапка на гитхабе не нужна. Это лишь поспособствует тому, что меньше людей ее прочтет.
>Если не смог решить проблему, дай минимальный пример кода и напиши, какую ошибку он выдает.
Не понимаю до сих пор почему так.
Еси закоментить строчки:
namespace Core;
use Core\Router;
То всё начинает нормально работать как бы.
Твой автозагрузчик довольно кривой. Ну например, в линуксе и маке разделителем каталогов является прямой слеш, а не обратный. Нужно заменять слеши в полном имени класса.
Также, в линуксе важен регистр букв в имени файлов и папок. Должно быть именно Core, с большой буквы.
Я бы советовал поставить в автозагрузчик вывод через echo имени класса и получившегося пути к файлу. И посмотреть, что выведется - правильные имена класса и файла или нет.
Помни, что автозагрузчик получает полное имя класса на вход, со всеми неймспейсами.
Также, всегда используй <?php вместо <? так как короткие php-теги могут быть отключены в конфиге.
То есть проблема в моем автозагрузчике, который я просто спиздил с дефолтного примера из интернета?
Если я пишу в index.php use Core\Router;
То он ищет его вот так:
string(51) "C:\OpenServer\domains\link.loc\Core\Core\Router.php"
Что делать то в итоге с этим?
Переделывать автозагрузчик. Пример, который дан в моем уроке (и который использован у тебя) - он ничего не знает про неймспейсы.
Тебе надо подумать, почитать в моем уроке про PSR-4 и написать поддерживающий этот стандарт автозагрузчик. Включая поддержку неймспейсов.
Также, в PHP уже есть реализация похожего на PSR-4 автозагрузчика: http://php.net/manual/ru/function.spl-autoload.php . По моему он не на 100% соответствует спецификации PSR-4. Было бы хорошо, если бы ты прочел документацию и проверил, соответствует он PSR-4 или нет, если нет, то в чем.
Можно использовать готовый автозагрузчик, но конечно написать сначала свой будет и интереснее и полезнее.
Спасибо, сейчас попытаюсь въехать. Алсо иметь в итоге в ооп-проекте старую добрую functions.php считается зашкваром или как? Или делают какой-то статический класс с глобальной видимостью что бы ему кормить когда нужно переменные?
И еще, пытаюсь тут понять про Dependency Injection, и у меня вопрос. А чем это по сути отличается от процедурной лапши?
Вместо обычной functionname() влюбом месте кода мы просто пишем в итоге
$this->someshit->functionname()
Как и всевозможные
$a = $this->config->get('varname);
по сути ни что иное как сделать:
global $config = array(...);
и писать в коде
$a = $config['varname'];
(\+\-\ 7|8\-\ \()(\d?\-\ \(\)*){10}
Вот как это вижу я:
первая часть: символ +, возможные пробелы-тире, 7 ИЛИ 8, возможные пробелы-тире-скобки;
вторая часть: цифра 0-9, возможные пробелы-тире-скобки, всё это повторить 10 раз.
ЧЯДНТ?
Статистических данных дохуя. Например есть таблица операций участников куда заносится тип операции в соответствии с которым у него отбавляются/прибавляются очки (изымаются/умножаются проценты в соответствии с кол-вом рефералов и прочими деталями). Лучше завести отдельную таблицу куда записывать эти цифры или подсчитывать их при загрузке станицы?
> При загрузке страницы подсчитывать число участников из БД или завести отдельную таблицу со всей статистикой, куда при регистрации нового участника просто добавлять единицу и соответственно при загрузке страницы отображать эту цифру?
Сделать кеширование (то есть либо отдельную ячейку в отдельной таблице, либо ячейку в кеше вроде redis). Так как запрос на подсчет числа записей в таблице требует полного ее обхода, и это будет медленно на больших таблицах.
Правда, если ты будешь прибавлять единичку при регистрации, может появиться расхождение между кешированным и реальным значением. Советую завернуть добавление пользователя и увеличение числа в транзакцию, а в случае редиса сделать крон-скрипт который будет периодиечски (например раз в сутки) подсчитывать реальное число и исправлять расхождение.
> Лучше завести отдельную таблицу куда записывать эти цифры или подсчитывать их при загрузке станицы?
Не знаю, зависит от того, какие запросы делаются, сколько записей приходится выбирать.
Кеширование и денормализация (добавление избыточных данных) - это по большому счеты костыли, которые имеют недостатки (необходимость поддерживать актуальность этих избыточных данных) и если можно без этого обойтись, то лучше ничего не кешировать.
>>1035603
Не очень понял вопрос, но вообще регулярки заточены под условия вроде "здесь должны быть такие символы", а с условиями "здесь не должно быть таких символов" они будут работать плохо.
Вместо того, чтобы что-то исключать, лучше переписать регулярку, чтобы эти символы в нее с самого начала не попадали. Или же сделать дополнительную проверку результатов поиска и исключать в ней.
По фрагменту регулярки (?!\w+$), трудно понять, праивльно ли она будет работать или нет.
У тебя код для поиска дополнительных символов (минусов, пробелов) задает определенный порядок, в котором они должны идти:
\-*\ *\(*\)*
Это значит "сначала любое число минусов, потом любое число пробелов, ..". Но если между цифрами идет последовательность "пробел, минус, пробел" то она не будет соответствовать этому выражению.
Нужно вместо него написать "любое число минусов, пробелов, скобок в любом порядке". Для этого ты сначала пишешь выражение "пробел, минус или скобка" (это можно сделать 2 способами: с помощью квадратных скобок, либо с помощью круглых скобок и вертикальной черты), а затем к нему добавляешь символ повторения любое число раз.
Также, минус вне квадратных скобок не требует экранирования бекслешем. Пробел не требует бекслеша.
Спецсимволы, которые надо экранировать, перечислены тут: http://php.net/manual/ru/regexp.reference.meta.php
Если у тебя каждый юзер постоянно влияет на других юзеров, и 1 его клик в системе вызывает цепную реакцию, то нагрузка на бд будет расти очень быстро. С поправкой конечно на то что число активных юзеров тоже постоянно растет. Если у тебя проект на 2000 тел то там не важно даже наверное как ты сделаешь. В статистике хостинга будешь видеть 1-5% нагрузку на бд в любом случае в пиковые моменты.
По опыту работы в похожей системе, лучше под каждую сущность будет запилить таблицу. Юзер - сущность. Его баланс - тоже отдельная сущность. Юзер покакал - тоже запись в бд. И уже с ними работать, а не на лету всё высчитывать постоянно.
Если не дай бог придется что-то кому-то вот так без записей в базе править, то это вставлять в код лютейшие костыли, вместо того что бы запись в базу добавить и прочее. Главное дублировния избежать грамотно.
Например закинул юзер на баланс бабло - пришло ему, ну и тем кто ему привел капнуло.
В базе у тебя просто +х к балансу юзера и +у к балансу реферала тикнуло. (Когда надо будет узнать баланс юзеров, то просто селект из этой таблички делается. просто и без нагрузки).
Но в другую табличку улетела инфа что сколько и когда кому за счет чего зачислилось. И по ней ты можешь изи всегда восстановить по крупицам откуда бабло и юзерята опять же могут смотреть детализацию и прочее.
А если у тебя одна таблица с пополнениями, и для каждого чиха ты делаешь из неё фулл селект и потом из него уже на лету всё складываешь и прочее - вскоре будет у всех всё тормозить.
Далее по поводу статистики. Можешь в отдельную таблицу вынести её, если её действительно много. И например раз в какое-то удобное для тебя время её пересчитывать. Кроном хуярить раз в 10 минут например все селекты и пересчеты с обновлением этой таблицы, в то время как юзеры будут простой легкий селект этой таблички дергать, без нагрузки на базу.
Всё зависит в итоге только какая нужна актуальность. Если у тебя подобие биржи какой-нибудь, и инфа должна всегда быть без задержки, то тогда и надо вокруг этого плясать - тут я хз.
Если у тебя каждый юзер постоянно влияет на других юзеров, и 1 его клик в системе вызывает цепную реакцию, то нагрузка на бд будет расти очень быстро. С поправкой конечно на то что число активных юзеров тоже постоянно растет. Если у тебя проект на 2000 тел то там не важно даже наверное как ты сделаешь. В статистике хостинга будешь видеть 1-5% нагрузку на бд в любом случае в пиковые моменты.
По опыту работы в похожей системе, лучше под каждую сущность будет запилить таблицу. Юзер - сущность. Его баланс - тоже отдельная сущность. Юзер покакал - тоже запись в бд. И уже с ними работать, а не на лету всё высчитывать постоянно.
Если не дай бог придется что-то кому-то вот так без записей в базе править, то это вставлять в код лютейшие костыли, вместо того что бы запись в базу добавить и прочее. Главное дублировния избежать грамотно.
Например закинул юзер на баланс бабло - пришло ему, ну и тем кто ему привел капнуло.
В базе у тебя просто +х к балансу юзера и +у к балансу реферала тикнуло. (Когда надо будет узнать баланс юзеров, то просто селект из этой таблички делается. просто и без нагрузки).
Но в другую табличку улетела инфа что сколько и когда кому за счет чего зачислилось. И по ней ты можешь изи всегда восстановить по крупицам откуда бабло и юзерята опять же могут смотреть детализацию и прочее.
А если у тебя одна таблица с пополнениями, и для каждого чиха ты делаешь из неё фулл селект и потом из него уже на лету всё складываешь и прочее - вскоре будет у всех всё тормозить.
Далее по поводу статистики. Можешь в отдельную таблицу вынести её, если её действительно много. И например раз в какое-то удобное для тебя время её пересчитывать. Кроном хуярить раз в 10 минут например все селекты и пересчеты с обновлением этой таблицы, в то время как юзеры будут простой легкий селект этой таблички дергать, без нагрузки на базу.
Всё зависит в итоге только какая нужна актуальность. Если у тебя подобие биржи какой-нибудь, и инфа должна всегда быть без задержки, то тогда и надо вокруг этого плясать - тут я хз.
Функции можно использовать, но стоит также рассмотреть возможность использовать utility-класс ( https://en.wikipedia.org/wiki/Helper_class ). Интересно, что при попытке погуглить "utility class" выпадает много результатов вроде "utility class pattern is evil", предлагаю читателю самостоятельно изучить указанные статьи и решить, веские ли аргументы там указаны.
Ну например, utility class дает возможность группировать функции по смыслу (впрочем, простые функции можно группировать по неймспейсам), автозагрузку.
Также, некоторые вещи (действия над объектами) в принципе неудобно реализовать на функциях. Ну например, работа с формами:
ООП:
$form = new RegisterForm;
$form->parseData($request);
if ($form->isValid()) { ..
То же самое на функциях писать будет неудобно:
$form = createRegisterForm();
formParseData($form, $request);
if (formIsValid($form)) { ...
Получается какая-то неуклюжая имитация ООП, где информация о форме ($form) передается первым аргументом.
> Или делают какой-то статический класс с глобальной видимостью что бы ему кормить когда нужно переменные?
Это называется utility class
> И еще, пытаюсь тут понять про Dependency Injection, и у меня вопрос. А чем это по сути отличается от процедурной лапши?
> В чем разница между
> $a = $this->config->get('varname');
> $a = getConfig('varname');
В первом случае мы обращаемся к конфигу в поле $this->config, в программе может быть много разных конфигов. Конфиг доступен не везде, а только там, куда мы его явно передали. Видно по конструктору, что классу для работы нужен конфиг. В случае функции конфиг во всей программе может быть только один (нельзя создать объект с другими настройками, а это часто нужно при тестировании), доступен он везде, даже там, где не нужен, не видно, кому он нужен, а кому нет.
Советую прочесть мой урок по DI ( https://github.com/codedokode/pasta/blob/master/arch/di.md ), если не читал, там это разбирается, чем плохи глобальные переменные, почему плохо, когда класс сам получает нужные ему настройки (или у тебя вопросы после прочтения появились?).
> global $config = array(...);
> $a = $config['varname'];
Этот вариант обладает всеми недостатками подхода с функцией, но еще хуже, чем функция, так как труднее разбирать код. Например, непонятно, как вообще найти место, где задается эта переменная, когда кода много. Также, поскольку переменная доступна глобально, мы не можем быть уверены, что где-то на полпути ее не меняют (например, какой-нибудь начинающий разработчик вполне может влепить такой хак). Также, непонятно, как проверить, в данном файле, существуют ли эта переменная или она еще не создана и надо что-то вызвать сначала, чтобы ее заполнить?
Замечу также, что идея передавать конфиг с кучей настроек не очень хорошая, красивее будет передавать в класс только нужные ему настройки. Это избавляет его от зависимости от объета конфига (классу не нужно знать как с ним работать, класс не надо менять при изменениях в объекте конфига), и дает классу только нужные ему настройки, а не весь конфиг целиком. Становится видно по конструктору, какие именно настройки нужны классу. И, например, это позволит использовать класс даже без объекта конфига.
Ну и я могу привести другие примеры, когда DI полезна. Ну например, возьмем объект соединения с БД. Допустим, у нас он самостоятельно берет параметры подключения из функции:
$dbal = new Dbal();
$dbal->makeQuery('SELECT .. FROM ...');
Вопрос: как с таким объектом сделать подключение к 2 разным БД? Тут как раз и поможет DI:
$dbal1 = new Dbal('db1', 'password1');
$dbal2 = new Dbal('db2', 'password2');
Ну и, как я уже упомянул выше, при тестировании часто требуется создать временный объект с другими (нестандартными) настройками, потестировать его и удалить. Подход с глобальным конгфигом не позволяет это сделать. Он делает код менее гибким, не дает возможности произвольно менять настройки отдельного класса.
Вот тебе задачка для размышлений. Допустим, нам в приложении нужна функция конвертации валют: на вход даем сумму в одной валюте (например, рубль), на выходе получаем сумму в долларах. Курс перевода необходимо брать с удаленного сервера (например, ЦБ РФ предоставляет API для получения курса). Однако, мы не хотим при каждой конвертации делать запрос в сеть, так как курс меняется раз в сутки, мы хотим сохранять этот курс локально (например, в файл или кеш вроде redis) и использовать его в течение суток.
Также, мы хотим протестировать эти функции по отдельности, а именно:
- проверить, что конвертация работает, с указанным явно в тесте курсом, не делая запросов
- проверить, что функция запроса курса с сервера работает, то есть возвращает адекватное число, при этом не сохранять результат никуда
- проверить, что кеширование работает, что курс в течение дня запрашивается только один раз
Также, мы бы хотели, чтобы при тестировании другого кода, который использует конвертор, не делалось никаких обращений к удаленным серверам, а использовался жестко заданный в тесте курс обмена.
Предложи свое решение, как бы ты организовал код (конкретный код писать не надо, достаточно просто названий функций/классов, что они принимают и по какому алгоритму работают).
Также, в моем уроке есть пункт "Пример использования преимуществ DI". Посмотри на написанный там код и предложит альтернативные варианты, как можно сделать такое же без DI или без ООП.
Если тебе что-то непонятно, спрашивай. Вопросы после прочтения урока помогают мне понять, что можно в нем улучшить.
Функции можно использовать, но стоит также рассмотреть возможность использовать utility-класс ( https://en.wikipedia.org/wiki/Helper_class ). Интересно, что при попытке погуглить "utility class" выпадает много результатов вроде "utility class pattern is evil", предлагаю читателю самостоятельно изучить указанные статьи и решить, веские ли аргументы там указаны.
Ну например, utility class дает возможность группировать функции по смыслу (впрочем, простые функции можно группировать по неймспейсам), автозагрузку.
Также, некоторые вещи (действия над объектами) в принципе неудобно реализовать на функциях. Ну например, работа с формами:
ООП:
$form = new RegisterForm;
$form->parseData($request);
if ($form->isValid()) { ..
То же самое на функциях писать будет неудобно:
$form = createRegisterForm();
formParseData($form, $request);
if (formIsValid($form)) { ...
Получается какая-то неуклюжая имитация ООП, где информация о форме ($form) передается первым аргументом.
> Или делают какой-то статический класс с глобальной видимостью что бы ему кормить когда нужно переменные?
Это называется utility class
> И еще, пытаюсь тут понять про Dependency Injection, и у меня вопрос. А чем это по сути отличается от процедурной лапши?
> В чем разница между
> $a = $this->config->get('varname');
> $a = getConfig('varname');
В первом случае мы обращаемся к конфигу в поле $this->config, в программе может быть много разных конфигов. Конфиг доступен не везде, а только там, куда мы его явно передали. Видно по конструктору, что классу для работы нужен конфиг. В случае функции конфиг во всей программе может быть только один (нельзя создать объект с другими настройками, а это часто нужно при тестировании), доступен он везде, даже там, где не нужен, не видно, кому он нужен, а кому нет.
Советую прочесть мой урок по DI ( https://github.com/codedokode/pasta/blob/master/arch/di.md ), если не читал, там это разбирается, чем плохи глобальные переменные, почему плохо, когда класс сам получает нужные ему настройки (или у тебя вопросы после прочтения появились?).
> global $config = array(...);
> $a = $config['varname'];
Этот вариант обладает всеми недостатками подхода с функцией, но еще хуже, чем функция, так как труднее разбирать код. Например, непонятно, как вообще найти место, где задается эта переменная, когда кода много. Также, поскольку переменная доступна глобально, мы не можем быть уверены, что где-то на полпути ее не меняют (например, какой-нибудь начинающий разработчик вполне может влепить такой хак). Также, непонятно, как проверить, в данном файле, существуют ли эта переменная или она еще не создана и надо что-то вызвать сначала, чтобы ее заполнить?
Замечу также, что идея передавать конфиг с кучей настроек не очень хорошая, красивее будет передавать в класс только нужные ему настройки. Это избавляет его от зависимости от объета конфига (классу не нужно знать как с ним работать, класс не надо менять при изменениях в объекте конфига), и дает классу только нужные ему настройки, а не весь конфиг целиком. Становится видно по конструктору, какие именно настройки нужны классу. И, например, это позволит использовать класс даже без объекта конфига.
Ну и я могу привести другие примеры, когда DI полезна. Ну например, возьмем объект соединения с БД. Допустим, у нас он самостоятельно берет параметры подключения из функции:
$dbal = new Dbal();
$dbal->makeQuery('SELECT .. FROM ...');
Вопрос: как с таким объектом сделать подключение к 2 разным БД? Тут как раз и поможет DI:
$dbal1 = new Dbal('db1', 'password1');
$dbal2 = new Dbal('db2', 'password2');
Ну и, как я уже упомянул выше, при тестировании часто требуется создать временный объект с другими (нестандартными) настройками, потестировать его и удалить. Подход с глобальным конгфигом не позволяет это сделать. Он делает код менее гибким, не дает возможности произвольно менять настройки отдельного класса.
Вот тебе задачка для размышлений. Допустим, нам в приложении нужна функция конвертации валют: на вход даем сумму в одной валюте (например, рубль), на выходе получаем сумму в долларах. Курс перевода необходимо брать с удаленного сервера (например, ЦБ РФ предоставляет API для получения курса). Однако, мы не хотим при каждой конвертации делать запрос в сеть, так как курс меняется раз в сутки, мы хотим сохранять этот курс локально (например, в файл или кеш вроде redis) и использовать его в течение суток.
Также, мы хотим протестировать эти функции по отдельности, а именно:
- проверить, что конвертация работает, с указанным явно в тесте курсом, не делая запросов
- проверить, что функция запроса курса с сервера работает, то есть возвращает адекватное число, при этом не сохранять результат никуда
- проверить, что кеширование работает, что курс в течение дня запрашивается только один раз
Также, мы бы хотели, чтобы при тестировании другого кода, который использует конвертор, не делалось никаких обращений к удаленным серверам, а использовался жестко заданный в тесте курс обмена.
Предложи свое решение, как бы ты организовал код (конкретный код писать не надо, достаточно просто названий функций/классов, что они принимают и по какому алгоритму работают).
Также, в моем уроке есть пункт "Пример использования преимуществ DI". Посмотри на написанный там код и предложит альтернативные варианты, как можно сделать такое же без DI или без ООП.
Если тебе что-то непонятно, спрашивай. Вопросы после прочтения урока помогают мне понять, что можно в нем улучшить.
Я может что-то не понимаю, но мне казалось, что депенденси инджекшн - это когда допустим работаешь с фреймворком, и прямо внутри контроллера можешь обратиться к модели через:
$this->modelName->methodName();
Ну и прочие встроенные во фреймворк штуки обычно точно так же уже доступны как я выше писал:
> $a = $this->config->get('varname');
Так вот для меня это как раз всё выглядит как тупо функциональный код.
Когда вместо
saveUserToDb($user);
тупо пишется:
$this->userModel->saveUser($user);
Теперь я вообще запутался
А прочел ли ты урок, ссылку на который я дал? Там многое объясняется.
Во-вторых, а прочел ли ты внимательно мой пост? Я же тебе написал, в чем разница.
В-третьих, это назывеатся, не функциональный, а процедурный код ( https://ru.wikipedia.org/wiki/Парадигма_программирования )
То, что ты упоминаешь, к DI отношения не имеет.
Так вот, собираюсь уже написать стартовую страницу но возникла проблема со структурой проекта.
Пожалуйста напишите ТОЧНУЮ файловую-структуру. Где какие папки и где что должно лежать, используя MVC.
Например:
Slim.loc (название проекта)
/scr/public
/scr/public/css
/scr/public/fonts
/scr/public/js
/scr/templates(он же views?)
/scr/models
/vendor
Пожалуйста.
А так же index.php(точка входа) и .htaccess должны лежать я так понимаю в /scr/public
Туда же скинуть и composer.json and composer .lock and .ignore?
>Самоучитель HTML4
Почему бы тебе не изучить документацию по Апачу (если ты его используешь)? Она правда большая и запутанная, но может дать какие-то идеи. Ну например, если нет возможности использовать htaccess, то можно вписать правила в конфиг Апача (хотя и этой возможности наверно не будет, если речь о каком-то нищехостинге с ограниченными правами).
Ну и непонятно, зачем там нужен яваскрипт, редирект делается через HTTP заголовки ответа.
>>1033764
Действительно, добавили такой оператор, я ошибся.
>>1033466
А ты читал вообще мануал по Eloquent?
Задаешь отношения между моделями как, например, описано тут: https://laravel.ru/docs/v5/eloquent-relationships
После чего легко можно получить связанные сущности, как описано в мануале. Затем делаешь метод $user->getRentedBooks() который получает, что тебе нужно. Это в любом случае лучше, чем публично доступное поле. Писать запросы и создавать объекты вручную скорее всего не надо, ORM сделает это за тебя.
>>1033386
Используй крон
>>1033269
В Го есть сборщик мусора например и синтаксис в некоторых местах более удобный, чем в Си++. И не надо писать деструкторы например.
>>1033263
Что значит "на Си++ мало пишут"? Откуда такая информация? Многие (топовые, а не от мамкиных самодельщиков) игры на Си++, офисные программы вроде Openoffice на Си++, браузер Хром на Си++, и еще куча софта.
Как я уже писал выше, производительность у него хорошая, но код на нем писать и отлаживать долго. Код быстро писать на HTML/JS, но производительность получается минимальная.
Почему бы тебе не изучить документацию по Апачу (если ты его используешь)? Она правда большая и запутанная, но может дать какие-то идеи. Ну например, если нет возможности использовать htaccess, то можно вписать правила в конфиг Апача (хотя и этой возможности наверно не будет, если речь о каком-то нищехостинге с ограниченными правами).
Ну и непонятно, зачем там нужен яваскрипт, редирект делается через HTTP заголовки ответа.
>>1033764
Действительно, добавили такой оператор, я ошибся.
>>1033466
А ты читал вообще мануал по Eloquent?
Задаешь отношения между моделями как, например, описано тут: https://laravel.ru/docs/v5/eloquent-relationships
После чего легко можно получить связанные сущности, как описано в мануале. Затем делаешь метод $user->getRentedBooks() который получает, что тебе нужно. Это в любом случае лучше, чем публично доступное поле. Писать запросы и создавать объекты вручную скорее всего не надо, ORM сделает это за тебя.
>>1033386
Используй крон
>>1033269
В Го есть сборщик мусора например и синтаксис в некоторых местах более удобный, чем в Си++. И не надо писать деструкторы например.
>>1033263
Что значит "на Си++ мало пишут"? Откуда такая информация? Многие (топовые, а не от мамкиных самодельщиков) игры на Си++, офисные программы вроде Openoffice на Си++, браузер Хром на Си++, и еще куча софта.
Как я уже писал выше, производительность у него хорошая, но код на нем писать и отлаживать долго. Код быстро писать на HTML/JS, но производительность получается минимальная.
Ошибки в твоем варианте:
- public должен быть отдельно от src, в src мы держим код, который не отдаем наружу
- папку models лучше не делать. В MVC почти все, кроме контроллеров и вида относится к модели, соответственно не имеет смысла условно говоря делать папку для 75% кода. Лучше сделать отдельно папку для валидаторов, отдельно для классов работы с БД и тд.
Если классов мало, можно вообще свалить их в src без подпапок.
Также, прочти про PSR-4. У меня есть урок на гитхабе.
> А так же index.php(точка входа) и .htaccess должны лежать я так понимаю в /scr/public
Да, в public
> Туда же скинуть и composer.json and composer .lock and .ignore?
Ты хочешь всем пользователя сайта раздавать эти файлы? Зачем?
Эти файлы обычно кладут в корень.
Идея папки public в том, чтобы сделать публично доступной только одну папку (ради безопасности), а не весь проект. И в нее мы кладем только то, что хотим раздавать через веб-сервер пользователям.
> и не знаю с чего начать.
Начни с вывода страницы с текстом Hello World используя Слим.
Еще часто templates делают отдельной папкой, чтобы в src был php-код, а в tenplates - шаблона на твиге.
Справедливости ради, проблема ведь не в том, что Го или Монго "плохие". Проблема в том, что это инструменты со своими особенностями, которые хорошо работают в одной ситуации и не очень хорошо - в другой. Но блогеры-идиоты вместо объективного сравнения засоряют интернет высказываниями вроде "в 2017 году вместо A все используют B", а пользователи-идиоты бездумно следуют этим советам.
Изучите технологии, их сильные и слабые стороны, сделайте сравнительное тестирование и после этого выбирайте.
Я уверен, что на каких-то задачах Го в умелых руках будет работать идеально. Не уверен, правда, что в руках начинающего.
>>1032941
Не знаю, но знаю что официальный мануал PHP можно скачать в формате chm, имея соответствующий просмотрщик, можно читать его без интернета.
Также, на тот же андроид реально установить PHP/MySQL/Апач (но надо помучаться), редактор кода и что-то пытаться кодить, хотя конечно на маленькой клавиатуре будет печатать неудобно.
Для начала, стоит почитать ответы на эти вопросы:
- https://unix.stackexchange.com/questions/12260/how-to-encrypt-messages-text-with-rsa-openssl
- https://stackoverflow.com/questions/7143514/how-to-encrypt-a-large-file-in-openssl-using-public-key
(нашел гуглением по openssl rsa).
Там в частности написано, что RSA шифрует одно число, а не сообщение. Чтобы зашифровать большое сообщение, его разбивают на блоки и шифруют их симметричным шифрованием, причем есть несколько вариантов (режимов), как связать эти блоки между собой, вроде CBC, ECB.
И вот это: https://www.sitepoint.com/encrypt-large-messages-asymmetric-keys-phpseclib/
> The nature of the RSA algorithm is such that it is only able to encrypt a limited amount of plaintext. For example, if your key size is 2048 bits, then you are limited to 256 bytes (at most) of plaintext data that can be encrypted
> The solution to the problem is to encrypt the message with a symmetric key, then asymmetrically encrypt the key and attach it to the message.
Также, гуглением я нашел такие функции:
- http://php.net/manual/ru/function.openssl-public-encrypt.php
- http://php.net/manual/ru/function.openssl-private-encrypt.php
Обрати внимание на комментарии под ними. Расширение openssl является лишь интерфейсом к библиотеке openssl, потому подробности стоит смотреть еще и в описании этой библиотеки, например https://wiki.openssl.org/index.php/Main_Page
Также, я еще нашел вот это: https://en.wikipedia.org/wiki/Public-key_cryptography#Examples
Тут есть примеры конкретных методов ( Examples of protocols using asymmetric key algorithms include ): S/MIME, GPG, Off-the-record-messaging. Посмотри их - так как всегда лучше брать проверенную схему шифрования, чем с нуля изобретать свою. GPG - известная программа для шифрования почты, OTR используется в джаббере.
То есть, придется еще немного поковыряться в теории, прежде чем браться за практику (если что, я сам эти протоколы толком не знаю).
--------------
> При регистрации пользователя мы генерируем закртый\открытый ключ
Это значит мы должны доверять серверу, раз сервер генерирует пару ключей, а не клиент.
> Почему нету метода RSA? Однако, в опциях создания ключа можно указать этот тип
Думаю, потому, что RSA это не поточный шифр (не шифр, которым можно зашифровать произвольно большое сообщение).
Если у тебя установлена библиотека (не расширение PHP) openssl, то там есть команды:
openssl list-cipher-algorithms - дает тот же список что функция в PHP, без RSA
openssl list-public-key-algorithms - дает список с RSA, DH, DSA, EC, HMAC, CMAC
То есть это алгоритм не поточного шифрования, а чего-то другого.
> Эти все методы сделаны на его основе?
Стоит погуглить названия методов и посмотреть в общих чертах, как они работают. Ну например, AES-128-CBC, гуглим:
- AES: симметричный алгоритм блочного шифрования (размер блока 128 бит, ключ 128/192/256 бит), принятый в качестве стандарта шифрования правительством США по результатам конкурса AES
- 128: очевидно, размер ключа
- CBC: Cipher block chaining - режим шифрования, определяющий правила шифрования большого сообщения из нескольких блоков ( https://ru.wikipedia.org/wiki/Режим_шифрования )
Или SEED-CBC - SEED is a block cipher developed by the Korea Information Security Agency (KISA)...SEED is a 16-round Feistel network with 128-bit blocks and a 128-bit key
> В комментариях сказано, что RSA начинает устаревать и пора переходить на ECDH вместе с EdDSA. Что вы думаете по этому поводу?
Это по моему немного разные вещи, RSA это протокол асимметричного шифрования, DH - обмен ключами. Увы, не знаю, что лучше. Может быть стоит погуглить и посмотреть.
> Насколько я помню, протокол Диффи - Хеллмана генерирует общий ключ на основе закрытых\открытых ключей. Можно ли сказать, что этот протокол приводит асимметричное шифрование к симметричному?
Нет, лучше говорить что это протокол обмена ключами (собеседники получают общий ключ, не раскрывая свои ключи и не позволяя перехватить общий ключ).
> Эллиптические кривые только добавляют надёжности, я правильно понимаю?
Не знаю.
> но я не уверен что библиотека которая содержится в PHP использует алгоритм RSA (там какие-то методы (ссылаюсь на тот же вопрос выше о методах)).
ну там упомянуто, что она предназначена для взаимодействия с openssl, так что наверно должно работать.
> каким образом функция openssl_encrypt() шифрует данные из этой строки.
Судя по коду расширения https://github.com/php/php-src/blob/master/ext/openssl/openssl.c , строка 6523, там идет примерно такой алгоритм:
> cipher_type = EVP_get_cipherbyname(method);
> cipher_ctx = EVP_CIPHER_CTX_new();
> php_openssl_load_cipher_mode(&mode, cipher_type);
> php_openssl_cipher_init(...)
> EVP_EncryptFinal(cipher_ctx, (unsigned char )ZSTR_VAL(outbuf) + outlen, &i)
> base64_str = php_base64_encode((unsigned char)ZSTR_VAL(outbuf), outlen);
> RETVAL_STR(base64_str);
Функции, начинающиеся с EVP - это сишные функции библиотеки OpenSSL, документация по которым есть например тут: https://www.openssl.org/docs/man1.1.0/crypto/EVP_EncryptFinal.html
php_openssl_load_cipher_mode() и php_openssl_cipher_init() описаны в том же файле расширения (openssl.c) и являются обертками над функциями OpenSSL.
Тут конечно лучше попробовать найти статью "как зашифровать что-нибудь библиотекой OpenSSL".
> Зачем разделять код на две части? Это не более чем прихоть автора?
Чтобы те, кому не нужна вторая часть, не грузили ее.
Для начала, стоит почитать ответы на эти вопросы:
- https://unix.stackexchange.com/questions/12260/how-to-encrypt-messages-text-with-rsa-openssl
- https://stackoverflow.com/questions/7143514/how-to-encrypt-a-large-file-in-openssl-using-public-key
(нашел гуглением по openssl rsa).
Там в частности написано, что RSA шифрует одно число, а не сообщение. Чтобы зашифровать большое сообщение, его разбивают на блоки и шифруют их симметричным шифрованием, причем есть несколько вариантов (режимов), как связать эти блоки между собой, вроде CBC, ECB.
И вот это: https://www.sitepoint.com/encrypt-large-messages-asymmetric-keys-phpseclib/
> The nature of the RSA algorithm is such that it is only able to encrypt a limited amount of plaintext. For example, if your key size is 2048 bits, then you are limited to 256 bytes (at most) of plaintext data that can be encrypted
> The solution to the problem is to encrypt the message with a symmetric key, then asymmetrically encrypt the key and attach it to the message.
Также, гуглением я нашел такие функции:
- http://php.net/manual/ru/function.openssl-public-encrypt.php
- http://php.net/manual/ru/function.openssl-private-encrypt.php
Обрати внимание на комментарии под ними. Расширение openssl является лишь интерфейсом к библиотеке openssl, потому подробности стоит смотреть еще и в описании этой библиотеки, например https://wiki.openssl.org/index.php/Main_Page
Также, я еще нашел вот это: https://en.wikipedia.org/wiki/Public-key_cryptography#Examples
Тут есть примеры конкретных методов ( Examples of protocols using asymmetric key algorithms include ): S/MIME, GPG, Off-the-record-messaging. Посмотри их - так как всегда лучше брать проверенную схему шифрования, чем с нуля изобретать свою. GPG - известная программа для шифрования почты, OTR используется в джаббере.
То есть, придется еще немного поковыряться в теории, прежде чем браться за практику (если что, я сам эти протоколы толком не знаю).
--------------
> При регистрации пользователя мы генерируем закртый\открытый ключ
Это значит мы должны доверять серверу, раз сервер генерирует пару ключей, а не клиент.
> Почему нету метода RSA? Однако, в опциях создания ключа можно указать этот тип
Думаю, потому, что RSA это не поточный шифр (не шифр, которым можно зашифровать произвольно большое сообщение).
Если у тебя установлена библиотека (не расширение PHP) openssl, то там есть команды:
openssl list-cipher-algorithms - дает тот же список что функция в PHP, без RSA
openssl list-public-key-algorithms - дает список с RSA, DH, DSA, EC, HMAC, CMAC
То есть это алгоритм не поточного шифрования, а чего-то другого.
> Эти все методы сделаны на его основе?
Стоит погуглить названия методов и посмотреть в общих чертах, как они работают. Ну например, AES-128-CBC, гуглим:
- AES: симметричный алгоритм блочного шифрования (размер блока 128 бит, ключ 128/192/256 бит), принятый в качестве стандарта шифрования правительством США по результатам конкурса AES
- 128: очевидно, размер ключа
- CBC: Cipher block chaining - режим шифрования, определяющий правила шифрования большого сообщения из нескольких блоков ( https://ru.wikipedia.org/wiki/Режим_шифрования )
Или SEED-CBC - SEED is a block cipher developed by the Korea Information Security Agency (KISA)...SEED is a 16-round Feistel network with 128-bit blocks and a 128-bit key
> В комментариях сказано, что RSA начинает устаревать и пора переходить на ECDH вместе с EdDSA. Что вы думаете по этому поводу?
Это по моему немного разные вещи, RSA это протокол асимметричного шифрования, DH - обмен ключами. Увы, не знаю, что лучше. Может быть стоит погуглить и посмотреть.
> Насколько я помню, протокол Диффи - Хеллмана генерирует общий ключ на основе закрытых\открытых ключей. Можно ли сказать, что этот протокол приводит асимметричное шифрование к симметричному?
Нет, лучше говорить что это протокол обмена ключами (собеседники получают общий ключ, не раскрывая свои ключи и не позволяя перехватить общий ключ).
> Эллиптические кривые только добавляют надёжности, я правильно понимаю?
Не знаю.
> но я не уверен что библиотека которая содержится в PHP использует алгоритм RSA (там какие-то методы (ссылаюсь на тот же вопрос выше о методах)).
ну там упомянуто, что она предназначена для взаимодействия с openssl, так что наверно должно работать.
> каким образом функция openssl_encrypt() шифрует данные из этой строки.
Судя по коду расширения https://github.com/php/php-src/blob/master/ext/openssl/openssl.c , строка 6523, там идет примерно такой алгоритм:
> cipher_type = EVP_get_cipherbyname(method);
> cipher_ctx = EVP_CIPHER_CTX_new();
> php_openssl_load_cipher_mode(&mode, cipher_type);
> php_openssl_cipher_init(...)
> EVP_EncryptFinal(cipher_ctx, (unsigned char )ZSTR_VAL(outbuf) + outlen, &i)
> base64_str = php_base64_encode((unsigned char)ZSTR_VAL(outbuf), outlen);
> RETVAL_STR(base64_str);
Функции, начинающиеся с EVP - это сишные функции библиотеки OpenSSL, документация по которым есть например тут: https://www.openssl.org/docs/man1.1.0/crypto/EVP_EncryptFinal.html
php_openssl_load_cipher_mode() и php_openssl_cipher_init() описаны в том же файле расширения (openssl.c) и являются обертками над функциями OpenSSL.
Тут конечно лучше попробовать найти статью "как зашифровать что-нибудь библиотекой OpenSSL".
> Зачем разделять код на две части? Это не более чем прихоть автора?
Чтобы те, кому не нужна вторая часть, не грузили ее.
Я вчера сам уже понял, но все равно спасибо,добра тебе ^_^
Твиг вообще актуален?
В чём реальное, а не рекламное преимущество перед шаблонами на обычном рнр?
Преимущество в удобстве. И какая реклама, он разве платный?
1. Наследование.
Допустим, есть две страницы, на одной выводятся 5 самых популярных записей, сайдбар, на второй странице эти же записи с пагинацией и сайдбар с другим контентом/стилями.
С твигом создаешь один общий шаблон и обозначаешь в нем блоками места, которые можно переопределить в дочернем шаблоне.
Без твига будет либо копипаст, либо дикие джунгли с условными операторами.
2. Множество функций и фильтров, например вместо
<?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8') ?>
{{ var|e }}
Или вообще включить экранирование по умолчанию (в последних версиях оно и так включено).
Еще вспомнил фичу, обращение через точку {{ variable.property }} работает как с массивами, так и с объектами, так что если понадобится извлекать из бд массивы, а не объекты, не придется переписывать представление (скобки и кавычки вместо стрелочек).
А, главное преимущество наверное в том, что писать на шаблонизаторе сможет верстальщик, который не знает PHP (бывает и такое разделение труда).
Но по сути да, это синтаксический сахар.
>Тут есть примеры конкретных методов ( Examples of protocols using asymmetric key algorithms include ): S/MIME, GPG, Off-the-record-messaging. Посмотри их - так как всегда лучше брать проверенную схему шифрования, чем с нуля изобретать свою. GPG - известная программа для шифрования почты, OTR используется в джаббере.
>То есть, придется еще немного поковыряться в теории, прежде чем браться за практику (если что, я сам эти протоколы толком не знаю).
Ок.
Может даже не придётся сильно погружаться в теорию, а изучить только библиотеку реализующую их.
Я нашёл вот эти вот:
http://php.net/manual/ru/ref.gnupg.php
Только почему-то я не вижу методов генерации ключей. Нужно найти другую в таком случае?
http://php.net/manual/ru/function.gnupg-import.php
http://php.net/manual/ru/function.gnupg-addencryptkey.php
http://php.net/manual/ru/function.gnupg-adddecryptkey.php
Почему несколько методов для добавления ключей?
Вообще, функции add..cryptkey выглядят довольно странно, в аргументы принимают отпечаток, а не сам ключи. Это и есть функции генерации ключей?
Отпечаток и подпись служат для одной цели - идентификации владельца ключа. Вы ранее советовали предусмотреть подпись, поэтому, имея возможность легко получить отпечаток, следует ли предусматривать ещё и подпись?
http://php.net/manual/ru/function.gnupg-addencryptkey.php#112979
>When you've successfully installed gnupg, you should define the GNUPGHOME environment variable and make sure the directory is writeable by the Apache user.
>putenv("GNUPGHOME=/var/www/example.com/.gnupg");
Почему ключи должны храниться где-то на диске?
https://openpgpjs.org/
https://github.com/openpgpjs/openpgpjs
https://github.com/openpgpjs/openpgpjs#getting-started
>Or just fetch a minified build under dist.
Они же предлагают это сделать в случае браузерной версии?
Я пробежался по этому коду (https://github.com/openpgpjs/openpgpjs/blob/master/dist/openpgp.js) и вроде там есть нужные функции. Сложно разобраться в их коде, очень всё запутанно, а в документации вообще некоторые страницы выдают 404.
https://openpgpjs.org/openpgpjs/doc/module-openpgp.html
https://openpgpjs.org/openpgpjs/doc/module-key.html
>encrypt(..., signature)
В отличии от php-библиотеки, js-библиотека использует подпись. Это одно и тоже, в этом случае?
https://openpgpjs.org/openpgpjs/doc/module-signature.html
>armoredText
Что такое armoredText?
http://php.net/manual/ru/function.gnupg-adddecryptkey.php
https://openpgpjs.org/openpgpjs/doc/module-openpgp.html (generateKey)
Обе эти функции используют passphrase, этой фразой шифруется приватный ключ и можно использовать эту опции в нашем случае?
https://openpgpjs.org/openpgpjs/doc/
>openpgp.encrypt(options).then
Зачем здесь может быть нужен Promise?
>> При регистрации пользователя мы генерируем закртый\открытый ключ
>Это значит мы должны доверять серверу, раз сервер генерирует пару ключей, а не клиент.
Для этого придётся усложнить код. Я оставлю это на дальнейшую реализацию (обмен ключами и др. данными через p2p), а пока пусть будет так.
>Тут есть примеры конкретных методов ( Examples of protocols using asymmetric key algorithms include ): S/MIME, GPG, Off-the-record-messaging. Посмотри их - так как всегда лучше брать проверенную схему шифрования, чем с нуля изобретать свою. GPG - известная программа для шифрования почты, OTR используется в джаббере.
>То есть, придется еще немного поковыряться в теории, прежде чем браться за практику (если что, я сам эти протоколы толком не знаю).
Ок.
Может даже не придётся сильно погружаться в теорию, а изучить только библиотеку реализующую их.
Я нашёл вот эти вот:
http://php.net/manual/ru/ref.gnupg.php
Только почему-то я не вижу методов генерации ключей. Нужно найти другую в таком случае?
http://php.net/manual/ru/function.gnupg-import.php
http://php.net/manual/ru/function.gnupg-addencryptkey.php
http://php.net/manual/ru/function.gnupg-adddecryptkey.php
Почему несколько методов для добавления ключей?
Вообще, функции add..cryptkey выглядят довольно странно, в аргументы принимают отпечаток, а не сам ключи. Это и есть функции генерации ключей?
Отпечаток и подпись служат для одной цели - идентификации владельца ключа. Вы ранее советовали предусмотреть подпись, поэтому, имея возможность легко получить отпечаток, следует ли предусматривать ещё и подпись?
http://php.net/manual/ru/function.gnupg-addencryptkey.php#112979
>When you've successfully installed gnupg, you should define the GNUPGHOME environment variable and make sure the directory is writeable by the Apache user.
>putenv("GNUPGHOME=/var/www/example.com/.gnupg");
Почему ключи должны храниться где-то на диске?
https://openpgpjs.org/
https://github.com/openpgpjs/openpgpjs
https://github.com/openpgpjs/openpgpjs#getting-started
>Or just fetch a minified build under dist.
Они же предлагают это сделать в случае браузерной версии?
Я пробежался по этому коду (https://github.com/openpgpjs/openpgpjs/blob/master/dist/openpgp.js) и вроде там есть нужные функции. Сложно разобраться в их коде, очень всё запутанно, а в документации вообще некоторые страницы выдают 404.
https://openpgpjs.org/openpgpjs/doc/module-openpgp.html
https://openpgpjs.org/openpgpjs/doc/module-key.html
>encrypt(..., signature)
В отличии от php-библиотеки, js-библиотека использует подпись. Это одно и тоже, в этом случае?
https://openpgpjs.org/openpgpjs/doc/module-signature.html
>armoredText
Что такое armoredText?
http://php.net/manual/ru/function.gnupg-adddecryptkey.php
https://openpgpjs.org/openpgpjs/doc/module-openpgp.html (generateKey)
Обе эти функции используют passphrase, этой фразой шифруется приватный ключ и можно использовать эту опции в нашем случае?
https://openpgpjs.org/openpgpjs/doc/
>openpgp.encrypt(options).then
Зачем здесь может быть нужен Promise?
>> При регистрации пользователя мы генерируем закртый\открытый ключ
>Это значит мы должны доверять серверу, раз сервер генерирует пару ключей, а не клиент.
Для этого придётся усложнить код. Я оставлю это на дальнейшую реализацию (обмен ключами и др. данными через p2p), а пока пусть будет так.
Не scr, а src (от source, сокращенное до 3 букв на манер линуксовых директорий).
Кстати, я думаю, можно писать и source, сейчас ведь нет таких ограничений на длину имени файлов.
>> К сожалению, у меня не получилось найти в ejs аналог функции nl2br и при этом чтобы экранировались тэги. В таком случае, будет приемлемым оставить этот костыль?
>nl2br не экранирует теги, она только заменяет \n на <br>, если я не путаю.
>
>Насколько я понял, у тебя проблема в том, что ejs экранирует данные и твой <br> выводится как текст? В документации ( https://github.com/mde/ejs/blob/master/docs/syntax.md ) написано что есть 2 вида тегов, один принимают текст, экранируют его и выводят, другой тег принимает HTML код и вставляет его как есть.
>
>В чем именно сложность-то? Можно сделать так <%- convertMessageToHtml(message) %>
Проблема в том что ejs вообще не переводит с помощью \n на новую строку. Нужно заменять его на <br>, но ejs экранирует его тоже.
Можно не экранировать, а фильтровать с помощью какого-нибудь стороннего html-фильтра, но всё равно нужно как-то заменить \n на <br>.
>> Я никак не могу придумать как выводить только новые сообщения. Определенно, нужен setTimeout\setInterval чтобы постоянно обновлять данные с сервера, но как при этом выводить только те сообщения которые ещё не выведены в шаблон?
>Для этого клиент должен "знать", какие сообщения выведены, и запрашивать с сервера только новые, и добавлять только новые. Чтобы это реализовать, нужно спроектировать изменения в нескольких компонентах:
>Для этого клиент должен "знать", какие сообщения выведены
Мне эта идея сразу пришла на ум, перед тем как я столкнулся с проблемой асинхронного получения данных - мы не можем сохранить список сообщений, а только их обещание. Вероятно, мы не можем даже к этому обещанию добавить ещё результаты, потому что, вероятно, если мы напишем
var messages = getMessages(...).then(...);
messages.then(...);
мы выполним тот же самый запрос getMessages(...) и получим тот же самый результат.
Поэтому, очевидным решением мне показалось взять "знание" о выведенных сообщениях прямо из DOM.
Ещё есть вариант сохранять сообщения в sessionStorage, где ключем будет ID сообщения, а значением сам его объект. Затем сравнивать программно результаты запросов и sessionStorage, и выводить\сохранять уникальные значения.
>> Не подвергаю ли я пользователей опасности, открывая кукисы для js?
>Нет наверно.
>> Я сомневаюсь что это будет правильным решением, но с другой стороны не вижу никакой проблемы. Как лучше поступить?
>А зачем тебе нужна кука в JS коде? Ведь при отправке аякс-запроса куки и так отправляются на сервер.
Чтобы вывести токен в шаблон формы для csrf-защиты.
>И конечно, странно, что у тебя token хранится в view.
Конечно, я вынесу его из view.
>> К сожалению, у меня не получилось найти в ejs аналог функции nl2br и при этом чтобы экранировались тэги. В таком случае, будет приемлемым оставить этот костыль?
>nl2br не экранирует теги, она только заменяет \n на <br>, если я не путаю.
>
>Насколько я понял, у тебя проблема в том, что ejs экранирует данные и твой <br> выводится как текст? В документации ( https://github.com/mde/ejs/blob/master/docs/syntax.md ) написано что есть 2 вида тегов, один принимают текст, экранируют его и выводят, другой тег принимает HTML код и вставляет его как есть.
>
>В чем именно сложность-то? Можно сделать так <%- convertMessageToHtml(message) %>
Проблема в том что ejs вообще не переводит с помощью \n на новую строку. Нужно заменять его на <br>, но ejs экранирует его тоже.
Можно не экранировать, а фильтровать с помощью какого-нибудь стороннего html-фильтра, но всё равно нужно как-то заменить \n на <br>.
>> Я никак не могу придумать как выводить только новые сообщения. Определенно, нужен setTimeout\setInterval чтобы постоянно обновлять данные с сервера, но как при этом выводить только те сообщения которые ещё не выведены в шаблон?
>Для этого клиент должен "знать", какие сообщения выведены, и запрашивать с сервера только новые, и добавлять только новые. Чтобы это реализовать, нужно спроектировать изменения в нескольких компонентах:
>Для этого клиент должен "знать", какие сообщения выведены
Мне эта идея сразу пришла на ум, перед тем как я столкнулся с проблемой асинхронного получения данных - мы не можем сохранить список сообщений, а только их обещание. Вероятно, мы не можем даже к этому обещанию добавить ещё результаты, потому что, вероятно, если мы напишем
var messages = getMessages(...).then(...);
messages.then(...);
мы выполним тот же самый запрос getMessages(...) и получим тот же самый результат.
Поэтому, очевидным решением мне показалось взять "знание" о выведенных сообщениях прямо из DOM.
Ещё есть вариант сохранять сообщения в sessionStorage, где ключем будет ID сообщения, а значением сам его объект. Затем сравнивать программно результаты запросов и sessionStorage, и выводить\сохранять уникальные значения.
>> Не подвергаю ли я пользователей опасности, открывая кукисы для js?
>Нет наверно.
>> Я сомневаюсь что это будет правильным решением, но с другой стороны не вижу никакой проблемы. Как лучше поступить?
>А зачем тебе нужна кука в JS коде? Ведь при отправке аякс-запроса куки и так отправляются на сервер.
Чтобы вывести токен в шаблон формы для csrf-защиты.
>И конечно, странно, что у тебя token хранится в view.
Конечно, я вынесу его из view.
Сори что долго не отвечал, то как я бы решал задчу значит в реальном проекте (у меня опыт работы только в небольших проектах)
Для начала в базе заводим табличку с курсом обмена в которой есть как минимум такие столбцы как: курс, дата выставления.
Далее пишу 3 функции, будь это просто в functions.php или методы модельного класса который будет отвечать за работу с баблом.
1. Добавляет в эту табличку новую запись курса обмена
2. Взять из таблички последнюю запись курса обмена.
3. Спросить с удаленного сервера текущий курс.
Далее значит такой код:
Спрашиваем с удаленного сервера курс
Спрашиваем последнюю запись с таблицы курсов.
Если курсы различаются, то добавляем новый курс в таблицу.
Это всё будет повешано на крон, и будет вызываться сколько-то там раз в сутки, в зависимости от того как часто на удаленном ресурсе меняется курс.
Ну а дальше всё просто.
Функция конвертации рубли в доллары в 2 строчки:
На вход курс и рубли, на выходе доллары.
В приложении когда юзер будет что-то хотеть сконвертить, то в контроллере который принимает юзерский инпут с рублями, будет примерно так всё:
Если есть инпут то валидируем инпут, если ок то:
Спрашиваем последнюю запись с таблицы курсов.
Кормим инпут и курс функции конвертации
Отдать ответ в массив инфы который полетит во вьюху.
иначе отдать сообщение что инпут неверен.
Сори что долго не отвечал, то как я бы решал задчу значит в реальном проекте (у меня опыт работы только в небольших проектах)
Для начала в базе заводим табличку с курсом обмена в которой есть как минимум такие столбцы как: курс, дата выставления.
Далее пишу 3 функции, будь это просто в functions.php или методы модельного класса который будет отвечать за работу с баблом.
1. Добавляет в эту табличку новую запись курса обмена
2. Взять из таблички последнюю запись курса обмена.
3. Спросить с удаленного сервера текущий курс.
Далее значит такой код:
Спрашиваем с удаленного сервера курс
Спрашиваем последнюю запись с таблицы курсов.
Если курсы различаются, то добавляем новый курс в таблицу.
Это всё будет повешано на крон, и будет вызываться сколько-то там раз в сутки, в зависимости от того как часто на удаленном ресурсе меняется курс.
Ну а дальше всё просто.
Функция конвертации рубли в доллары в 2 строчки:
На вход курс и рубли, на выходе доллары.
В приложении когда юзер будет что-то хотеть сконвертить, то в контроллере который принимает юзерский инпут с рублями, будет примерно так всё:
Если есть инпут то валидируем инпут, если ок то:
Спрашиваем последнюю запись с таблицы курсов.
Кормим инпут и курс функции конвертации
Отдать ответ в массив инфы который полетит во вьюху.
иначе отдать сообщение что инпут неверен.
Сделал первую часть TestHub.
https://github.com/pricklynut/testhub
Накопилось некоторое кол-во вопросов.
Симфони странно себя ведет после установки, я имею ввиду точки входа.
Если сначала запросить корень сайта / напрямую, выдает 500.
Однако если зайти на /app.php, редиректит на /, и с этого момента
/ доступен напрямую. Однако если почистить кеш, та же фигня. Что он там
кеширует, это так и должно быть?
Странно, больше не повторяется.
update: развернул на другом компе, теперь наоборот редиректит с / на /app.php.
htaccess стандартный, который идет в комплекте с фреймворком.
через раз (буквально) вылетает ошибка
php bin/console cache:clear --no-warmup -e prod
PHP Notice: Undefined index: host in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 6
PHP Notice: Undefined index: port in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 7
PHP Notice: Undefined index: user in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 9
PHP Notice: Undefined index: pass in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 10
PHP Fatal error: Uncaught PDOException: SQLSTATE[08006] [7] ВАЖНО: база данных "connect_timeout=30" не существует in /home/inside/www/testhub.com/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:43
Я понял, что он не может подключиться к бд, но почему через раз, что за магия? Там настройки подключения к бд берутся из переменной среды, но почему один раз эта переменная доступна, другой нет? Переменная среды объявлена в конфиге виртуального хоста.
Как в симфони делать виджеты? В yii виджет это просто класс, который подставляет
переменные из своего конфига в шаблон и возвращает эту строку.
Например echo SidebarWidget::widget(['class' => 'abc', 'title' => 'asdfad']);
В симфони не понимаю, как из модели вызвать render какого-нибудь шаблона.
Допустим, я хотел сделать виджет для пагинации. Класс написал, шаблон пришлось положить
к общим шаблонам, хотя как бы он относится именно к виджету, а не к проекту.
Странно, что в бутстрапе в пагинации текущая страница и неактивная ссылка на предыдущую
содержат кликабельную ссылку. По-моему эти ссылки вообще нужно удалить, но если
это сделать, ломается верстка.
По структуре проекта на симфони: куды вообще что писать?
Представления-вьюшки кидать в app/Resources, или в аналогичную папку AppBundle?
Стили, js, тоже в AppBundle/Resources?
Еще в контроллерах у меня скопилось много логики, не знаю куда ее вынести. В модели (entity)
не получится, там нет доступа в бд.
В репозитории тоже как-то неуместно, по сути репозитории должны только извлекать из бд сущности,
желательно одноименные с названием репозитория или связанные.
Короче нужны советы по рефакторингу этого дела.
Пока почитаю, как сделать добавление новых тестов.
Нужно именно одной формой, сам тест, все его вопросы, все варианты ответов на каждый вопрос?
Какая-то жесть получается, а если в тесте сто вопросов по 8 вариантов на каждый? И если на 69 вопросе
пользователь случайно закроет браузер, начинать все сначала? Может, сохранять куда-то (куда?)
промежуточные данные в процессе редактирования?
Пока не представляю как это делать.
Сделал первую часть TestHub.
https://github.com/pricklynut/testhub
Накопилось некоторое кол-во вопросов.
Симфони странно себя ведет после установки, я имею ввиду точки входа.
Если сначала запросить корень сайта / напрямую, выдает 500.
Однако если зайти на /app.php, редиректит на /, и с этого момента
/ доступен напрямую. Однако если почистить кеш, та же фигня. Что он там
кеширует, это так и должно быть?
Странно, больше не повторяется.
update: развернул на другом компе, теперь наоборот редиректит с / на /app.php.
htaccess стандартный, который идет в комплекте с фреймворком.
через раз (буквально) вылетает ошибка
php bin/console cache:clear --no-warmup -e prod
PHP Notice: Undefined index: host in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 6
PHP Notice: Undefined index: port in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 7
PHP Notice: Undefined index: user in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 9
PHP Notice: Undefined index: pass in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 10
PHP Fatal error: Uncaught PDOException: SQLSTATE[08006] [7] ВАЖНО: база данных "connect_timeout=30" не существует in /home/inside/www/testhub.com/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php:43
Я понял, что он не может подключиться к бд, но почему через раз, что за магия? Там настройки подключения к бд берутся из переменной среды, но почему один раз эта переменная доступна, другой нет? Переменная среды объявлена в конфиге виртуального хоста.
Как в симфони делать виджеты? В yii виджет это просто класс, который подставляет
переменные из своего конфига в шаблон и возвращает эту строку.
Например echo SidebarWidget::widget(['class' => 'abc', 'title' => 'asdfad']);
В симфони не понимаю, как из модели вызвать render какого-нибудь шаблона.
Допустим, я хотел сделать виджет для пагинации. Класс написал, шаблон пришлось положить
к общим шаблонам, хотя как бы он относится именно к виджету, а не к проекту.
Странно, что в бутстрапе в пагинации текущая страница и неактивная ссылка на предыдущую
содержат кликабельную ссылку. По-моему эти ссылки вообще нужно удалить, но если
это сделать, ломается верстка.
По структуре проекта на симфони: куды вообще что писать?
Представления-вьюшки кидать в app/Resources, или в аналогичную папку AppBundle?
Стили, js, тоже в AppBundle/Resources?
Еще в контроллерах у меня скопилось много логики, не знаю куда ее вынести. В модели (entity)
не получится, там нет доступа в бд.
В репозитории тоже как-то неуместно, по сути репозитории должны только извлекать из бд сущности,
желательно одноименные с названием репозитория или связанные.
Короче нужны советы по рефакторингу этого дела.
Пока почитаю, как сделать добавление новых тестов.
Нужно именно одной формой, сам тест, все его вопросы, все варианты ответов на каждый вопрос?
Какая-то жесть получается, а если в тесте сто вопросов по 8 вариантов на каждый? И если на 69 вопросе
пользователь случайно закроет браузер, начинать все сначала? Может, сохранять куда-то (куда?)
промежуточные данные в процессе редактирования?
Пока не представляю как это делать.
> Проблема в том что ejs вообще не переводит с помощью \n на новую строку.
А почему он должен? Он просто выводит этот \n в итоговый HTML, а дальше уже браузер его игнорирует.
Нужно использовать функцию, заменяющую \n на <br> и экранирующую спецсиволы, и выводить результат через неэкранирующий тег (<%- ... ). Либо, как альтернативу, можно использовать свойство CSS white-space, чтобы переводы строк выводились как в исходном коде: https://developer.mozilla.org/ru/docs/Web/CSS/white-space
> Нужно заменять его на <br>, но ejs экранирует его тоже.
Нужно использовать неэкранирующий тег для вывода (разумеется, тогда спецсимволы нужно экранировать самостоятельно).
> Вероятно, мы не можем даже к этому обещанию добавить ещё результаты, потому что, вероятно, если мы напишем
> var messages = getMessages(...).then(...);
> messages.then(...);
> мы выполним тот же самый запрос getMessages(...) и получим тот же самый результат.
Нет, второй раз запрос не выполнится. Просто последний then() получит на вход значение, которое вернул через return предпоследний then.
> Ещё есть вариант сохранять сообщения в sessionStorage, где ключем будет ID сообщения, а значением сам его объект. Затем сравнивать программно результаты запросов и sessionStorage, и выводить\сохранять уникальные значения.
Вообще, мне кажется, ты немного все переусложняешь. Достаточно с сервера вместе с сообщениями присылать время получения данных, и при следующем запросе просить сервер прислать только сообщения, добавленные/обновленные после этого времени.
>>А зачем тебе нужна кука в JS коде?
> Чтобы вывести токен в шаблон формы для csrf-защиты.
Можно брать данные из куки, или можно просто с сервера присылать токен при авторизации и дальше его использовать.
>>1039102
Я думаю, что нет.
> Проблема в том что ejs вообще не переводит с помощью \n на новую строку.
А почему он должен? Он просто выводит этот \n в итоговый HTML, а дальше уже браузер его игнорирует.
Нужно использовать функцию, заменяющую \n на <br> и экранирующую спецсиволы, и выводить результат через неэкранирующий тег (<%- ... ). Либо, как альтернативу, можно использовать свойство CSS white-space, чтобы переводы строк выводились как в исходном коде: https://developer.mozilla.org/ru/docs/Web/CSS/white-space
> Нужно заменять его на <br>, но ejs экранирует его тоже.
Нужно использовать неэкранирующий тег для вывода (разумеется, тогда спецсимволы нужно экранировать самостоятельно).
> Вероятно, мы не можем даже к этому обещанию добавить ещё результаты, потому что, вероятно, если мы напишем
> var messages = getMessages(...).then(...);
> messages.then(...);
> мы выполним тот же самый запрос getMessages(...) и получим тот же самый результат.
Нет, второй раз запрос не выполнится. Просто последний then() получит на вход значение, которое вернул через return предпоследний then.
> Ещё есть вариант сохранять сообщения в sessionStorage, где ключем будет ID сообщения, а значением сам его объект. Затем сравнивать программно результаты запросов и sessionStorage, и выводить\сохранять уникальные значения.
Вообще, мне кажется, ты немного все переусложняешь. Достаточно с сервера вместе с сообщениями присылать время получения данных, и при следующем запросе просить сервер прислать только сообщения, добавленные/обновленные после этого времени.
>>А зачем тебе нужна кука в JS коде?
> Чтобы вывести токен в шаблон формы для csrf-защиты.
Можно брать данные из куки, или можно просто с сервера присылать токен при авторизации и дальше его использовать.
>>1039102
Я думаю, что нет.
> Только почему-то я не вижу методов генерации ключей. Нужно найти другую в таком случае?
Для начала, надо разобраться, что это за расширение и как оно вообще работает. Идем сюда: http://php.net/manual/ru/gnupg.installation.php , отсюда сюда: http://pecl.php.net/package/gnupg и тут видим "wrapper around the gpgme library". Находим мануал к этой библиотеке: https://www.gnupg.org/documentation/manuals/gpgme/
К сожалению, в мануале разобраться сложно, потому пойдем другим путем. Упомянутая там библиотека GPGME - это библиотека, которая позволяет выполнять те же функции, что и команда gpg, только вызывая их программно. Потому почитаем мануал по gpg ( https://www.gnupg.org/gph/en/manual.html ). Там это явно не написано (видимо все и так должны это знать), но можно догадаться, что у этой программы есть хранилище ключей (keyring) - по сути просто файл в домашнем каталоге пользователя. И ты можешь генерировать новые ключи, а также импортировать ключи других людей в этот самый keyring. И при подписывании/шифровании/проверке подписи/расшифровке испоьзуются именно ключи из keyring.
То есть если ты хочешь с кем-то вести зашифрованную переписку, ты добавляешь его (публичный) ключ в свой keyring сначала. Для удобства обмена ключами там есть специальные серверы ключей и программа умеет сама получать публичный ключ контакта с такого сервера (например по email или по отпечатку ключа).
Теперь принцип работы функций из gnupg становится понятен. Если мы откроем пример кода из мануала: http://php.net/manual/ru/gnupg.examples-clearsign.php
> // добавить ключ для подписания с паролем 'test'
> $gnupg->addsignkey("8660281B6051D071D94B5B230549F9DC851566DC", "test");
Эта команда загружает ключ с указанным отпечатком (отпечаток - это по сути хеш от содержимого ключа, который можно считать его уникальным идентификатором, так как у разных ключей они будут разные) из keyring в память (куда-то внутрь объекта $gnupg) и позволяет использовать его в следующей строке:
> $signed = $gnupg->sign("просто тест");
Соответственно, вот что получается:
> Только почему-то я не вижу методов генерации ключей.
Это можно сделать утилитой командной строки gpg. Вообще, в самой сишной библиотеке есть функция генерации ключа, но в расширении она не доступна.
> Почему несколько методов для добавления ключей?
Наверно потому что это ключи для разных целей.
> Вообще, функции add..cryptkey выглядят довольно странно, в аргументы принимают отпечаток, а не сам ключи
Они ищут ключ внутри keyring по отпечатку.
> Почему ключи должны храниться где-то на диске?
Потому что так задумано, это программа для одного пользователя, с помощью которой он подписывает и шифрует файлы и переписку.
>>Or just fetch a minified build under dist.
> Они же предлагают это сделать в случае браузерной версии?
Думаю, что там код универсальный, который работает и в ноде и в браузере.
> В отличии от php-библиотеки, js-библиотека использует подпись. Это одно и тоже, в этом случае?
Нет. PHP библиотека использовала отпечаток (fingerprint), чтобы идентифицировать ключ в keyring, а здесь другое:
> signature Signature (optional) a detached signature to add to the encrypted message
Это подпись в отдельном файле (сгенерированная ранее из документа, который мы хотим зашифровать), которую можно прикрепить к зашифрованному документу.
> Что такое armoredText?
Нужно почитать мануал к gpg:
> Create ASCII-armored output that can be safely e-mailed, instead of binary output:
> -a, --armor
Это значит, что данные представлены в виде печатаемых символов (текста), и их можно например скопировать и переслать в письме или опублировать (то есть вроде кодировки base64). Другой вариант - это использовать бинарное кодирование, когда данные представлены просто в виде набора байт, которые могут не соответствовать тексту (так как в utf-8 например не все последовательности байт соответствуют символам, и при попытке скопировать кракозябры что-то может потеряться). Бинарный формат компактнее.
> Обе эти функции используют passphrase, этой фразой шифруется приватный ключ и можно использовать эту опции в нашем случае?
Не знаю, возможно, что да. Эта библиотека позволяет шифроватьт данные в браузере, что конечно хорошо, так как не требует передавать сами сообщения на сервер. Но не знаю, как там будет с производительностью.
> Зачем здесь может быть нужен Promise?
Там шифрование делается в Web Worker. Вебворкер - это скрипт, выполняющийся в отдельном изолированном окружении, не имеющий доступа к DOM, который может общаться с основным скриптом на странице с помощью сообщений. Вебворкеры позволяют задействовать несколько ядер процессора, так как их код может выполняться параллельно с основным скриптом и не блокирует интерфейс браузера (в отличие от обычного яваскрипт кода, который выполняется в контексте страницы). Так как шифрование может быть тяжелым в вычислительном плане, в библиотеке используются вебворкеры, чтобы выполнять его параллельно с другими действиями.
Так как код шифрования выполняется где-то в другом потоке, он выполняется асинхронно, мы посылаем сообщение в тот поток, и через какое-то время в ответном сообщении приходит результат. Потому и промисы.
Почитай про веб воркеры: https://developer.mozilla.org/ru/docs/DOM/Using_web_workers
То есть, тебе стоило бы для начала хотя бы немного изучить теорию про gpg (может даже попробовать что-нибудь ей зашифровать), и почитать про веб-воркеры.
Вообще, opengpg мне кажется хорошей идеей, можно испоьзовать отлаженные алгоритмы вместо изобретения своих. Просто прикрутить к этому удобный, человеческий интерфейс. И вроде у них испоьзуется Asm.JS, который в фаерфоексе позволяет получить производительсноть близкую к производительности нативного кода (увы, вебкит его не поддерживает).
Плюс, я тут подумал, может это позволит как-то интегрироваться с GPG, то есть, например, обмениваться сообщениями с теми, кто использует обычную почту с шифрованием через gpg.
> Только почему-то я не вижу методов генерации ключей. Нужно найти другую в таком случае?
Для начала, надо разобраться, что это за расширение и как оно вообще работает. Идем сюда: http://php.net/manual/ru/gnupg.installation.php , отсюда сюда: http://pecl.php.net/package/gnupg и тут видим "wrapper around the gpgme library". Находим мануал к этой библиотеке: https://www.gnupg.org/documentation/manuals/gpgme/
К сожалению, в мануале разобраться сложно, потому пойдем другим путем. Упомянутая там библиотека GPGME - это библиотека, которая позволяет выполнять те же функции, что и команда gpg, только вызывая их программно. Потому почитаем мануал по gpg ( https://www.gnupg.org/gph/en/manual.html ). Там это явно не написано (видимо все и так должны это знать), но можно догадаться, что у этой программы есть хранилище ключей (keyring) - по сути просто файл в домашнем каталоге пользователя. И ты можешь генерировать новые ключи, а также импортировать ключи других людей в этот самый keyring. И при подписывании/шифровании/проверке подписи/расшифровке испоьзуются именно ключи из keyring.
То есть если ты хочешь с кем-то вести зашифрованную переписку, ты добавляешь его (публичный) ключ в свой keyring сначала. Для удобства обмена ключами там есть специальные серверы ключей и программа умеет сама получать публичный ключ контакта с такого сервера (например по email или по отпечатку ключа).
Теперь принцип работы функций из gnupg становится понятен. Если мы откроем пример кода из мануала: http://php.net/manual/ru/gnupg.examples-clearsign.php
> // добавить ключ для подписания с паролем 'test'
> $gnupg->addsignkey("8660281B6051D071D94B5B230549F9DC851566DC", "test");
Эта команда загружает ключ с указанным отпечатком (отпечаток - это по сути хеш от содержимого ключа, который можно считать его уникальным идентификатором, так как у разных ключей они будут разные) из keyring в память (куда-то внутрь объекта $gnupg) и позволяет использовать его в следующей строке:
> $signed = $gnupg->sign("просто тест");
Соответственно, вот что получается:
> Только почему-то я не вижу методов генерации ключей.
Это можно сделать утилитой командной строки gpg. Вообще, в самой сишной библиотеке есть функция генерации ключа, но в расширении она не доступна.
> Почему несколько методов для добавления ключей?
Наверно потому что это ключи для разных целей.
> Вообще, функции add..cryptkey выглядят довольно странно, в аргументы принимают отпечаток, а не сам ключи
Они ищут ключ внутри keyring по отпечатку.
> Почему ключи должны храниться где-то на диске?
Потому что так задумано, это программа для одного пользователя, с помощью которой он подписывает и шифрует файлы и переписку.
>>Or just fetch a minified build under dist.
> Они же предлагают это сделать в случае браузерной версии?
Думаю, что там код универсальный, который работает и в ноде и в браузере.
> В отличии от php-библиотеки, js-библиотека использует подпись. Это одно и тоже, в этом случае?
Нет. PHP библиотека использовала отпечаток (fingerprint), чтобы идентифицировать ключ в keyring, а здесь другое:
> signature Signature (optional) a detached signature to add to the encrypted message
Это подпись в отдельном файле (сгенерированная ранее из документа, который мы хотим зашифровать), которую можно прикрепить к зашифрованному документу.
> Что такое armoredText?
Нужно почитать мануал к gpg:
> Create ASCII-armored output that can be safely e-mailed, instead of binary output:
> -a, --armor
Это значит, что данные представлены в виде печатаемых символов (текста), и их можно например скопировать и переслать в письме или опублировать (то есть вроде кодировки base64). Другой вариант - это использовать бинарное кодирование, когда данные представлены просто в виде набора байт, которые могут не соответствовать тексту (так как в utf-8 например не все последовательности байт соответствуют символам, и при попытке скопировать кракозябры что-то может потеряться). Бинарный формат компактнее.
> Обе эти функции используют passphrase, этой фразой шифруется приватный ключ и можно использовать эту опции в нашем случае?
Не знаю, возможно, что да. Эта библиотека позволяет шифроватьт данные в браузере, что конечно хорошо, так как не требует передавать сами сообщения на сервер. Но не знаю, как там будет с производительностью.
> Зачем здесь может быть нужен Promise?
Там шифрование делается в Web Worker. Вебворкер - это скрипт, выполняющийся в отдельном изолированном окружении, не имеющий доступа к DOM, который может общаться с основным скриптом на странице с помощью сообщений. Вебворкеры позволяют задействовать несколько ядер процессора, так как их код может выполняться параллельно с основным скриптом и не блокирует интерфейс браузера (в отличие от обычного яваскрипт кода, который выполняется в контексте страницы). Так как шифрование может быть тяжелым в вычислительном плане, в библиотеке используются вебворкеры, чтобы выполнять его параллельно с другими действиями.
Так как код шифрования выполняется где-то в другом потоке, он выполняется асинхронно, мы посылаем сообщение в тот поток, и через какое-то время в ответном сообщении приходит результат. Потому и промисы.
Почитай про веб воркеры: https://developer.mozilla.org/ru/docs/DOM/Using_web_workers
То есть, тебе стоило бы для начала хотя бы немного изучить теорию про gpg (может даже попробовать что-нибудь ей зашифровать), и почитать про веб-воркеры.
Вообще, opengpg мне кажется хорошей идеей, можно испоьзовать отлаженные алгоритмы вместо изобретения своих. Просто прикрутить к этому удобный, человеческий интерфейс. И вроде у них испоьзуется Asm.JS, который в фаерфоексе позволяет получить производительсноть близкую к производительности нативного кода (увы, вебкит его не поддерживает).
Плюс, я тут подумал, может это позволит как-то интегрироваться с GPG, то есть, например, обмениваться сообщениями с теми, кто использует обычную почту с шифрованием через gpg.
Меньше писать приходится, синтакси более лаконичный. А вообще, это подробно разобрано на сайте самого твига: https://twig.symfony.com/
>>1039991
Ну, табличку и функции работы с ней можно вместе назвать "кеш курсов валют". Там при желании можно и другое хранилище использовать, это не принципиально. Но у меня там были еще дополнительные пожелания к коду:
> Также, мы хотим протестировать эти функции по отдельности, а именно:
> - проверить, что конвертация работает, с указанным явно в тесте курсом, не делая запросов
> - проверить, что функция запроса курса с сервера работает, то есть возвращает адекватное число, при этом не сохранять результат никуда
> - проверить, что кеширование работает, что курс в течение дня запрашивается только один раз
То есть я хотел чтобы ты разбил код на 3 отдельных независимых модуля - модуль конвертации, модуль кеширования курса (который хранит курс в табличке) и модуль для получения курса с сервера. Чтобы эти модули можно было бы тестировать по отдельности. Очевидно, что в предложенном тобой коде такого разбиения нет, все эти функции взаимосвязаны и их нельзя использовать по отдельности.
Один из вариантов реализовать код как несколько независимых модулей - использовать ООП и упоминавшийся где-то выше Dependeny Injection. В моем уроке по DI ( https://github.com/codedokode/pasta/blob/master/arch/di.md ) есть похожий пример кода, с разбиением на отдельные классы.
Вообще, это можно сделать и без ООП, на функциях, но выглядеть это все равно будет именно как имитация объектов на функциях и массивах. Хотя, может, есть и какие-то другие подходы, не знаю.
Если ты хочешь понять, как именно, то для начала нужно хорошо разобраться в ООП, потом изучить DI, ну а потом наверно у тебя появятся идеи, что можно сделать. Чтобы разобраться в ООП, я тебе могу посоветовать взять мой учебник из ОП поста, и там прочитать главу про ООП и решить задачи в ней (если только ты их уже не решил).
Пока в этом, но я думаю, что надо переходить в новый тред, а тут останутся только ответы на старые посты.
> Однако если зайти на /app.php, редиректит на /, и с этого момента / доступен напрямую. Однако если почистить кеш, та же фигня. Что он там кеширует, это так и должно быть?
Нет, не должно быть, это баг либо у тебя, либо в коде Симфони, хорошо бы добиться его устойчивого повторения и разобраться в причине.
Ну вообще да, Симфони много чего кеширует, в том числе в файлах. Например, кешируется содержание конфигов, метаданные сущностей Доктрины, шаблоны twig. В dev-режиме Симфони отслеживает даты модификации исходного кода и обновляет кеши при их изменении, а в продакшен-режиме не отслеживает, и рассчитывает, что ты запустишь специальную команду (по моему cache:warmup или как-то так), чтобы принудительно обновить кеш. Соответственно, скорее всего ты использовал у себя продакшен-режим, и работал с кешем, основанным на старых версиях файлов.
Ну и конечно нужно разобраться, по документации или исходникам, что именно кешируется, как и когда обновляется. Без этого Симфони пользоваться вообще нельзя. Ты должен по памяти знать все кеши.
> PHP Notice: Undefined index: host in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 6
Я догадываюсь в чем причина, но полезнее будет, если ты сам разберешься.
> Там настройки подключения к бд берутся из переменной среды, но почему один раз эта переменная доступна, другой нет? Переменная среды объявлена в конфиге виртуального хоста.
То есть эта переменная доступна только внутри Апача и процессов, которые из него запускаются. А когда ты в командной строке запускаешь код, откуда она там возьмется? Очевидно, ее там нет.
> Как в симфони делать виджеты?
Нет готового решения? Нельзя виджет представить в виде объекта с данными, и отдельного шаблона twig, в который мы передаем этот объект?
> В симфони не понимаю, как из модели вызвать render какого-нибудь шаблона.
В MVC за отображение данных отвечает Вид, а модель ничего не рендерит.
> Допустим, я хотел сделать виджет для пагинации. Класс написал, шаблон пришлось положить к общим шаблонам, хотя как бы он относится именно к виджету, а не к проекту.
Можно сделать для таких шаблонов отдельную папку, например, views/widgets/. И сделать объект, содержащий информацию о пагинации (число страниц, текущая страница и тд). Я вижу, у тебя есть класс, представляющий пагинацию.
Также, в Симфони есть бандлы, можно сделать бандл и в него класть виджеты, но не вижу выгоды.
> Странно, что в бутстрапе в пагинации текущая страница и неактивная ссылка на предыдущую содержат кликабельную ссылку
Можно вместо <a> использовать <span> для текущей страницы и ссылки не будет.
> По-моему эти ссылки вообще нужно удалить, но если это сделать, ломается верстка.
Нужно спан поставить, смотри мануал по бутстрапу.
> Представления-вьюшки кидать в app/Resources, или в аналогичную папку AppBundle?
Насчет бандлов, там не все так просто. Вообще бандлы - это что-то вроде библиотек, или даже мини-приложений, так как бандл может содержать свои шаблоны, сущности доктрины, контроллеры, сервисы, параметры конфига. Ну например, можно форум или блог оформить как бандл так, что его можно добавить на любой сайт на Симфони и все будет работать из коробки. Это описано тут: https://symfony.com/doc/current/bundles/best_practices.html
Если тебе такая возможность не требуется, то по идее ты оформляешь свое приложение как один AppBundle. Но в новых версиях Симфони все идет к тому, чтобы вообще отказаться от AppBundle и испоьзовать просто папку app или src, вот почитай:
- https://knpuniversity.com/screencast/symfony3-upgrade/new-dir-structure
- http://fabien.potencier.org/symfony4-directory-structure.html
То есть бандлы останутся только для библиотек. Приложение будет писаться без бандлов.
По поводу твоего вопроса, ответ на него тут: http://symfony.com/doc/current/quick_tour/the_architecture.html
> app/
> The application configuration, templates and translations.
Шаблоны в Симфони 3 должны быть тут.
> Стили, js, тоже в AppBundle/Resources?
Можно в web, если ты не используешь управление статикой (assetic например).
> Еще в контроллерах у меня скопилось много логики, не знаю куда ее вынести.
В сервисы (они же хелперы). Прочитай внимательно мой урок по MVC: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Ну вот например createAndPersistUser(), createAndPersistAttempt - явно не в контроллере должны быть. Только желательно придумать аккуратную архитектуру, чтобы функции не были в беспорядке раскиданы по классам, а как-то логично организованы.
Условно говоря, должна быть возможность сделать любые действия, которые делаются через веб-интерфейс, программно. Например: создать тест, удалить, ответить на него, и тд. То есть сервисы - это что-то вроде внутреннего API, через которое можно делать нужные действия. Задача контроллера лишь интерпретировать запрос пользователя и вызвать требуемое действие.
Потому я бы советовал сесть и спроектировать это внутреннее АПИ, решить, какие будут сервисы, за что каждый будет отвечать, какие в них будут действия.
> В модели (entity) не получится, там нет доступа в бд.
модель это не только entity и не только код работы с БД, почитай мой урок про MVC
> Нужно именно одной формой, сам тест, все его вопросы, все варианты ответов на каждый вопрос?
Лучше сделать так, как будет удобнее пользователю. То есть на одной странице с яваскриптом. У меня там есть пример страницы с тестом вроде бы.
> Какая-то жесть получается, а если в тесте сто вопросов по 8 вариантов на каждый?
Согласен, тут надо подумать. Можно например как-то сворачивать вопросы. Это ведь наверно удобнее, чем перезагружать страницу несколько раз, пока не найдешь вопрос.
> Может, сохранять куда-то (куда?) промежуточные данные в процессе редактирования?
Можно в localStorage, можно на сервер в фоновом режиме.
-----
По коду: если у тебя требуется PHP7, то напиши это в composer.json, сейчас там указан php5.
По поводу Симфони: там есть одна вещь, которая мне не нравится. Они в продакшене (в отличие от dev) не превращают ошибки в исключения и не используют strict_variables в твиге. Я думаю, это плохая идея и надо переделать это. Это идет вразрез в принципом fail fast и способствует более низкому качеству кода.
По роутеру: не советую использовать аннотации, когда роуты собраны в одном месте, намного удобнее.
В модели данных не увидел наследования, ты не думал, что для разных типов вопросов/ответов можно было бы использовать разные классы?
Если в таблицах у колонок есть значения по умолчанию, они должны быть продублированы в сущностях.
В Postgres можно использовать CHECK на колонках для ограничения вставляемых значений.
Поиск данных через связи не всегда эффективен.
Пока код выгодит нормально, надо только контроллер разгрузить.
Также, если есть время и возможность, советую подумать про добавление автоматизированных тестов, в ОП посте есть урок. Раз за Симфони взялся, надо бы и тестирование подучить.
Пока в этом, но я думаю, что надо переходить в новый тред, а тут останутся только ответы на старые посты.
> Однако если зайти на /app.php, редиректит на /, и с этого момента / доступен напрямую. Однако если почистить кеш, та же фигня. Что он там кеширует, это так и должно быть?
Нет, не должно быть, это баг либо у тебя, либо в коде Симфони, хорошо бы добиться его устойчивого повторения и разобраться в причине.
Ну вообще да, Симфони много чего кеширует, в том числе в файлах. Например, кешируется содержание конфигов, метаданные сущностей Доктрины, шаблоны twig. В dev-режиме Симфони отслеживает даты модификации исходного кода и обновляет кеши при их изменении, а в продакшен-режиме не отслеживает, и рассчитывает, что ты запустишь специальную команду (по моему cache:warmup или как-то так), чтобы принудительно обновить кеш. Соответственно, скорее всего ты использовал у себя продакшен-режим, и работал с кешем, основанным на старых версиях файлов.
Ну и конечно нужно разобраться, по документации или исходникам, что именно кешируется, как и когда обновляется. Без этого Симфони пользоваться вообще нельзя. Ты должен по памяти знать все кеши.
> PHP Notice: Undefined index: host in /home/pricklynut/www/testhub.com/app/config/parameters_prod.php on line 6
Я догадываюсь в чем причина, но полезнее будет, если ты сам разберешься.
> Там настройки подключения к бд берутся из переменной среды, но почему один раз эта переменная доступна, другой нет? Переменная среды объявлена в конфиге виртуального хоста.
То есть эта переменная доступна только внутри Апача и процессов, которые из него запускаются. А когда ты в командной строке запускаешь код, откуда она там возьмется? Очевидно, ее там нет.
> Как в симфони делать виджеты?
Нет готового решения? Нельзя виджет представить в виде объекта с данными, и отдельного шаблона twig, в который мы передаем этот объект?
> В симфони не понимаю, как из модели вызвать render какого-нибудь шаблона.
В MVC за отображение данных отвечает Вид, а модель ничего не рендерит.
> Допустим, я хотел сделать виджет для пагинации. Класс написал, шаблон пришлось положить к общим шаблонам, хотя как бы он относится именно к виджету, а не к проекту.
Можно сделать для таких шаблонов отдельную папку, например, views/widgets/. И сделать объект, содержащий информацию о пагинации (число страниц, текущая страница и тд). Я вижу, у тебя есть класс, представляющий пагинацию.
Также, в Симфони есть бандлы, можно сделать бандл и в него класть виджеты, но не вижу выгоды.
> Странно, что в бутстрапе в пагинации текущая страница и неактивная ссылка на предыдущую содержат кликабельную ссылку
Можно вместо <a> использовать <span> для текущей страницы и ссылки не будет.
> По-моему эти ссылки вообще нужно удалить, но если это сделать, ломается верстка.
Нужно спан поставить, смотри мануал по бутстрапу.
> Представления-вьюшки кидать в app/Resources, или в аналогичную папку AppBundle?
Насчет бандлов, там не все так просто. Вообще бандлы - это что-то вроде библиотек, или даже мини-приложений, так как бандл может содержать свои шаблоны, сущности доктрины, контроллеры, сервисы, параметры конфига. Ну например, можно форум или блог оформить как бандл так, что его можно добавить на любой сайт на Симфони и все будет работать из коробки. Это описано тут: https://symfony.com/doc/current/bundles/best_practices.html
Если тебе такая возможность не требуется, то по идее ты оформляешь свое приложение как один AppBundle. Но в новых версиях Симфони все идет к тому, чтобы вообще отказаться от AppBundle и испоьзовать просто папку app или src, вот почитай:
- https://knpuniversity.com/screencast/symfony3-upgrade/new-dir-structure
- http://fabien.potencier.org/symfony4-directory-structure.html
То есть бандлы останутся только для библиотек. Приложение будет писаться без бандлов.
По поводу твоего вопроса, ответ на него тут: http://symfony.com/doc/current/quick_tour/the_architecture.html
> app/
> The application configuration, templates and translations.
Шаблоны в Симфони 3 должны быть тут.
> Стили, js, тоже в AppBundle/Resources?
Можно в web, если ты не используешь управление статикой (assetic например).
> Еще в контроллерах у меня скопилось много логики, не знаю куда ее вынести.
В сервисы (они же хелперы). Прочитай внимательно мой урок по MVC: https://github.com/codedokode/pasta/blob/master/arch/mvc.md
Ну вот например createAndPersistUser(), createAndPersistAttempt - явно не в контроллере должны быть. Только желательно придумать аккуратную архитектуру, чтобы функции не были в беспорядке раскиданы по классам, а как-то логично организованы.
Условно говоря, должна быть возможность сделать любые действия, которые делаются через веб-интерфейс, программно. Например: создать тест, удалить, ответить на него, и тд. То есть сервисы - это что-то вроде внутреннего API, через которое можно делать нужные действия. Задача контроллера лишь интерпретировать запрос пользователя и вызвать требуемое действие.
Потому я бы советовал сесть и спроектировать это внутреннее АПИ, решить, какие будут сервисы, за что каждый будет отвечать, какие в них будут действия.
> В модели (entity) не получится, там нет доступа в бд.
модель это не только entity и не только код работы с БД, почитай мой урок про MVC
> Нужно именно одной формой, сам тест, все его вопросы, все варианты ответов на каждый вопрос?
Лучше сделать так, как будет удобнее пользователю. То есть на одной странице с яваскриптом. У меня там есть пример страницы с тестом вроде бы.
> Какая-то жесть получается, а если в тесте сто вопросов по 8 вариантов на каждый?
Согласен, тут надо подумать. Можно например как-то сворачивать вопросы. Это ведь наверно удобнее, чем перезагружать страницу несколько раз, пока не найдешь вопрос.
> Может, сохранять куда-то (куда?) промежуточные данные в процессе редактирования?
Можно в localStorage, можно на сервер в фоновом режиме.
-----
По коду: если у тебя требуется PHP7, то напиши это в composer.json, сейчас там указан php5.
По поводу Симфони: там есть одна вещь, которая мне не нравится. Они в продакшене (в отличие от dev) не превращают ошибки в исключения и не используют strict_variables в твиге. Я думаю, это плохая идея и надо переделать это. Это идет вразрез в принципом fail fast и способствует более низкому качеству кода.
По роутеру: не советую использовать аннотации, когда роуты собраны в одном месте, намного удобнее.
В модели данных не увидел наследования, ты не думал, что для разных типов вопросов/ответов можно было бы использовать разные классы?
Если в таблицах у колонок есть значения по умолчанию, они должны быть продублированы в сущностях.
В Postgres можно использовать CHECK на колонках для ограничения вставляемых значений.
Поиск данных через связи не всегда эффективен.
Пока код выгодит нормально, надо только контроллер разгрузить.
Также, если есть время и возможность, советую подумать про добавление автоматизированных тестов, в ОП посте есть урок. Раз за Симфони взялся, надо бы и тестирование подучить.
Также, те, кому я еще не ответил, напомните о себе в новом треде
>> Ещё есть вариант сохранять сообщения в sessionStorage, где ключем будет ID сообщения, а значением сам его объект. Затем сравнивать программно результаты запросов и sessionStorage, и выводить\сохранять уникальные значения.
>Вообще, мне кажется, ты немного все переусложняешь. Достаточно с сервера вместе с сообщениями присылать время получения данных, и при следующем запросе просить сервер прислать только сообщения, добавленные/обновленные после этого времени.
У меня приходила подобная мысль, только использовать не время, а ID последнего сообщения, но у меня, как всегда, возникают трудности с обработкой обещаний.
>> Вероятно, мы не можем даже к этому обещанию добавить ещё результаты, потому что, вероятно, если мы напишем
>> var messages = getMessages(...).then(...);
>> messages.then(...);
>> мы выполним тот же самый запрос getMessages(...) и получим тот же самый результат.
>Нет, второй раз запрос не выполнится. Просто последний then() получит на вход значение, которое вернул через return предпоследний then.
Значит можно будет написать так
function chat() {
this.messages;
}
chat.runMessages(...) {
this.messages = getMessages(...).then(...);
refreshMessages(...);
}
chat.refreshMessages(...) {
this.messages.then(
function(messages) {
// Получаем дату\ID последнего сообщения
var lastDate = messages.lastMessage.date;
// Получаем новые сообщения
getNewMessages(lastDate).then(
function(data) {
//Выводим новые сообщения
showMessages(data);
// и добавляем их к остальным
messages.lastMessage = data.lastMessage;
var length = Object.keys(messages.m).length; // m - хэш с самими сообщениями
for (var key in data.m) {
messages.m[length] = data.m[key];
length++;
}
return messages;
},
...
);
return messages;
},
...
);
}
Я ведь правильно объединил массивы сообщений из двух разных обещаний?
>> Ещё есть вариант сохранять сообщения в sessionStorage, где ключем будет ID сообщения, а значением сам его объект. Затем сравнивать программно результаты запросов и sessionStorage, и выводить\сохранять уникальные значения.
>Вообще, мне кажется, ты немного все переусложняешь. Достаточно с сервера вместе с сообщениями присылать время получения данных, и при следующем запросе просить сервер прислать только сообщения, добавленные/обновленные после этого времени.
У меня приходила подобная мысль, только использовать не время, а ID последнего сообщения, но у меня, как всегда, возникают трудности с обработкой обещаний.
>> Вероятно, мы не можем даже к этому обещанию добавить ещё результаты, потому что, вероятно, если мы напишем
>> var messages = getMessages(...).then(...);
>> messages.then(...);
>> мы выполним тот же самый запрос getMessages(...) и получим тот же самый результат.
>Нет, второй раз запрос не выполнится. Просто последний then() получит на вход значение, которое вернул через return предпоследний then.
Значит можно будет написать так
function chat() {
this.messages;
}
chat.runMessages(...) {
this.messages = getMessages(...).then(...);
refreshMessages(...);
}
chat.refreshMessages(...) {
this.messages.then(
function(messages) {
// Получаем дату\ID последнего сообщения
var lastDate = messages.lastMessage.date;
// Получаем новые сообщения
getNewMessages(lastDate).then(
function(data) {
//Выводим новые сообщения
showMessages(data);
// и добавляем их к остальным
messages.lastMessage = data.lastMessage;
var length = Object.keys(messages.m).length; // m - хэш с самими сообщениями
for (var key in data.m) {
messages.m[length] = data.m[key];
length++;
}
return messages;
},
...
);
return messages;
},
...
);
}
Я ведь правильно объединил массивы сообщений из двух разных обещаний?
Не понимаю что значит модули. Это когда библиотеку типа пишешь, а потом её подгружают все кто хочет и в коде у себя использует?
Под каждый модуль писать класс?
И всё таки не понятно что такое DI и DI-контейнер. В двух словах можно описать как-нибудь какую он проблему именно решает и что делает?
Очень сложно когда все кругом говорят языком продакшена или другими заумными терминами, а по факту от тебя хотят не такие уж и сложные вещи, но ты просто не можешь понять.
Модуль здесь значит "обособленная часть приложения". "Обособленная" - значит как-то отделенная от других частей, не спутанная с ними и выполняющая свою, отдельную задачу. Способная работать отдельно.
Я не стал писать "класс", так как это подразумевало бы использование ООП, а код на фукциях тоже по идее можно поделить на модули (например, разложив функции по разным файлам или неймспейсам).
Соответственно, если код разбит на обособленные модули, то с ним может быть проще работать. Можно изучать и править отдельный модуль, не трогая другие модули и не боясь сломать что-то еще.
То есть модуль может быть файлом с функциями, классом, набором классов и тд, в зависимости от ситуации. Главное чтобы у него была какая-то своя задача и он был обособлен от других модулей, не спутан с ними слишком сильно. В ООП обычно один модуль - это один класс (но не всегда).
И конечно, если хочется оформить модуль в виде библиотеки, то это нетрудно сделать. Но это не обязательно.
Соответственно, если вернуться к задаче про конвертер валют, я бы хотел, чтобы отдельные части этого конвертера были обособлены.
Ну например, чтобы "загрузчик курсов с внешнего API" был отдельным модулем и мы могли бы использовать или тестировать его отдельно. Чтобы мы могли например вызвать какую-то функцию и она бы сделала нужные запросы и вернула нам курс, полученный с сервера.
И я хотел, чтобы сам конвертер был бы отделен от кеша курсов и загрузчика курсов. Чтобы мы могли например дать ему жестко заданный курс, и протестировать, как он конвертирует суммы по этому курсу, не используя кеш и внешний сервис.
А то, что ты описал, не разбито на модули. У тебя по твоему описанию все эти части спутаны и зависят одна от другой.
------
DI (dependency injection) - это внедрение зависимостей в ООП. Это подход, когда классу передают его зависимости снаружи ("внедряют"), а не он ищет или получает их самостоятельно. Что такое "зависимость", описано в моем уроке про DI ( https://github.com/codedokode/pasta/blob/master/arch/di.md )
Чтобы понять DI, нужно сначала изучить и понять ООП. Скорее всего ты пока его не понимаешь, потому для тебя все, что описано в том уроке, звучит непонятно. Потому, я тебе могу предложить решить задачу про Вектор и Кошки-мышки из учебника в ОП посте, если ты их еще не решал.
Или, может быть, ты решил эти задачи, и понимаешь ООП, но ты пока не сталкивался со случаями, когда надо передавать зависимости. В таком случае, могу предложить задачу про студентво из ОП поста - там DI понадобится.
> Очень сложно когда все кругом говорят языком продакшена или другими заумными терминами, а по факту от тебя хотят не такие уж и сложные вещи, но ты просто не можешь понять.
Ты скорее всего просто пропустил какие-то базовые вещи, берешься сразу за сложное, оттого и не понимаешь.
Модуль здесь значит "обособленная часть приложения". "Обособленная" - значит как-то отделенная от других частей, не спутанная с ними и выполняющая свою, отдельную задачу. Способная работать отдельно.
Я не стал писать "класс", так как это подразумевало бы использование ООП, а код на фукциях тоже по идее можно поделить на модули (например, разложив функции по разным файлам или неймспейсам).
Соответственно, если код разбит на обособленные модули, то с ним может быть проще работать. Можно изучать и править отдельный модуль, не трогая другие модули и не боясь сломать что-то еще.
То есть модуль может быть файлом с функциями, классом, набором классов и тд, в зависимости от ситуации. Главное чтобы у него была какая-то своя задача и он был обособлен от других модулей, не спутан с ними слишком сильно. В ООП обычно один модуль - это один класс (но не всегда).
И конечно, если хочется оформить модуль в виде библиотеки, то это нетрудно сделать. Но это не обязательно.
Соответственно, если вернуться к задаче про конвертер валют, я бы хотел, чтобы отдельные части этого конвертера были обособлены.
Ну например, чтобы "загрузчик курсов с внешнего API" был отдельным модулем и мы могли бы использовать или тестировать его отдельно. Чтобы мы могли например вызвать какую-то функцию и она бы сделала нужные запросы и вернула нам курс, полученный с сервера.
И я хотел, чтобы сам конвертер был бы отделен от кеша курсов и загрузчика курсов. Чтобы мы могли например дать ему жестко заданный курс, и протестировать, как он конвертирует суммы по этому курсу, не используя кеш и внешний сервис.
А то, что ты описал, не разбито на модули. У тебя по твоему описанию все эти части спутаны и зависят одна от другой.
------
DI (dependency injection) - это внедрение зависимостей в ООП. Это подход, когда классу передают его зависимости снаружи ("внедряют"), а не он ищет или получает их самостоятельно. Что такое "зависимость", описано в моем уроке про DI ( https://github.com/codedokode/pasta/blob/master/arch/di.md )
Чтобы понять DI, нужно сначала изучить и понять ООП. Скорее всего ты пока его не понимаешь, потому для тебя все, что описано в том уроке, звучит непонятно. Потому, я тебе могу предложить решить задачу про Вектор и Кошки-мышки из учебника в ОП посте, если ты их еще не решал.
Или, может быть, ты решил эти задачи, и понимаешь ООП, но ты пока не сталкивался со случаями, когда надо передавать зависимости. В таком случае, могу предложить задачу про студентво из ОП поста - там DI понадобится.
> Очень сложно когда все кругом говорят языком продакшена или другими заумными терминами, а по факту от тебя хотят не такие уж и сложные вещи, но ты просто не можешь понять.
Ты скорее всего просто пропустил какие-то базовые вещи, берешься сразу за сложное, оттого и не понимаешь.
Помогите с проблемой.
Кароч есть скрипт для CLI. Изначально был сделан для работы в связке с AJAX. AJAX продолжал вызывать скрипт с разными параметрами, пока не было встречено определенное условие. Затем поставили задачу переделать под работу с CRON. CRON подходит в качестве инициатора, но не связующего звена, т.к. может выполняться не чаще раза в минуту, а скрипт должен вызывать сам себя, как только текущая операция завершена.
Сделал следующее:
передал register_shutdown_function коллбэк, в котором делаю дисконнект с БД и затем использую команду passthru, чтобы начать следующую итерацию.
В итоге столкнулся с проблемой "открыто слишком много файлов". Скрипт выполняет под рутом и где-то на 50-ой итерации php крашится, т.к. рут превышает ulimit использования файлов.
Подозреваю, что это вызвано тем, что изначальный скрипт никогда толком не завершается и ждет результата выполнения passthru. По сути, получается рекурсия, которая сжирает ресурсы.
Вопрос: как решить задачу связывания вызовов скрипта и при этом высвобождать ресурсы?
Это копия, сохраненная 11 августа 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.