• Как через php скачать файл и назвать его так как он был назван?

    @alpeg
    как мне узнать какое расширение у файла

    Сервер отдаёт имя файла в заголовке Content-Disposition в полях filename и/или в filename*.
    И тут есть два способа сохранить файл с этим именем и/или расширением из этого имени:
    1) включить в curl CURLOPT_HEADER и вытащить заголовок вместе с содержимым за один запрос. Ссылку на то как это сделать уже дал SagePtr.
    2) отправить сначала HEAD-запрос, в котором посмотреть заголовок ответа, а затем вторым запросом скачать файл.
    В обоих случаях надо парсить заголовок ответа Content-Disposition
    Ответ написан
    Комментировать
  • Как парсить сайты защищенные CloudFront?

    @alpeg
    Обход кеша целиком и полностью зависит от настроек сайта, тут без экспериментов не разобраться.
    Пробуйте перебирать заголовки, GET-параметры, Сookie.
    Рекомендую почитать документацию самого CloudFront, особенно разделы про Query String Parameters, Cookies и Request Headers.
    Ответ написан
    Комментировать
  • Может кто подсказать программу для изменения свойств папки(win10)?

    @alpeg
    То, что Вы хотите, можно конечно сделать с помощью AutoIt, Autohotkey и подобных программ, но там сложнее.
    Самый простой способ - качаем программу Nirsoft WinExplorer v1.30 https://www.nirsoft.net/utils/winexp.html (внизу "Download WinExplorer (84KB)")
    запускаем, и вот тут очень важно - программа сканирует все окна но НЕ делает это в реальном времени. Если не находите что-то, надо нажимать "Refresh" чтобы получить свежие данные. Далее находим нужное окно, в нём - нужный элемент (надо поискать в других элементах) и внизу меняем текст.
    5f69268c5c37f411432605.png
    Ответ написан
    Комментировать
  • Как реализовать грамотную авторизацию PHP?

    @alpeg
    Грамотная авторизация делается вот как:
    Генерируем токен, ставим его пользователю в кукисы и пишем его в базу. Когда пришел запрос, проверяем, активен ли токен, и не протух ли, если всё ок, даём доступ, нет - шлём на авторизацию.
    Сессия для этого кстати необязательна. А, ну ещё второй токен, для CSRF. его тоже просто в кукисы.
    и там и там кукисы secure + httpOnly.
    Всё остальное - вариации на тему. Свои велосипеды городить не рекомендуется ввиду того, что они всегда приводят к дырам.

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

    Специально сгенерированный хэш - плохая идея, только абсолютно рандомный токен.
    Шифровать пароль и прочее в куку - очень плохая идея, забудьте.
    Шифровать userid и права - только в виде JWT, свой велосипед не городить, вечных и долгих токенов не давать (пусть обновляют, это обязательно).
    Ответ написан
  • Можно ли отследить факт скачивания потокового видео?

    @alpeg
    Если кратко, то почти никак.

    Если долго, то вообще можно, но на 100% не спасёт. Самые злые пользователи - всё равно скачают/запишут, ну и будут вас ненавидеть.

    Во-первых, вам придётся вместо CDN или просто загрузки файлов делать выдавать каждому пользователю отдельную ссылку, которая будет работать только однажды и только в браузере.
    Проанализировав отправляемые заголовки и время реакции (например, браузер с большой вероятностью отправит один запрос и сразу, или несколько, но с заголовком Range), можно с довольно большой точностью прикинуть, смотрит ли видео пользователь или качает. Если user-agent - wget, то точно бот, но если нет, то не факт что не бот.
    Сложность: выше среднего, эффективность: слабая (отрубит совсем тупых скрипт-киддисов)
    Ограничения для пользователей: небольшие

    Во-вторых, можно нарезать видео и собирать на клиенте через js. И на клиенте сделать что-то вроде DRM-модуля, который будет пытаться угадать, смотрит ли видео клиент. И отдавать следующие фрагменты видео, только если клиент не делает ничего подозрительного.
    Если клиент вдруг быстро качает целиком сразу много кусков (при нормальном воспроизведении такого быть не может, так как время ещё не пришло, а при перемотке он должен "прыгать" на кусок в середине), можно почти достоверно судить, что пользователь - бот/качает видео.
    Хорошим плюсом будет давать скачать первые две серии а на третей дать другой js-код плеера, собирающий серии по-другому.
    Сложность: высокая, эффективность: средняя (скорее всего пользователи забьют и запишут видео с экрана)
    Ограничения для пользователей: небольшие

    В-третьих, можно купить/лицензировать DRM.
    Сложность: очень высокая, Стоимость: очень высокая, эффективность: выше среднего (порог вхождения повыше, видео всё равно скачают, но если пользователей - три с половиной калеки, то никто заморачиваться не будет)
    Ограничения для пользователей: огромные. не все платформу поддерживают DRM.
    Ответ написан
    Комментировать
  • Ошибка при запуске сервера на React, как исправить?

    @alpeg
    Обновление node.js решает проблему.

    =====
    Внимание! Если нужная вам версия ноды не ставится на Windows 7 (требует Windows 8+) то нужно:
    UPD:
    вариант 1. просто установить LTS версию
    вариант 2. Только если нужна именно не-LTS версия, я вынес подробную инструкцию в комментарий.
    Ответ написан
  • Как заставить функцию работать асинхронно?

    @alpeg
    Правильная промисификация выглядит так - функция без ключевого слова async, но при её вызове нужен await или .then()
    function foo(path) {
    	return new Promise((resolve,reject)=>{
    		fs.readFile(`./server/db/${path}.json`, 'utf-8', (err, data) => {err ? reject(err) : resolve(data); });
    	});
    }
    // await foo('bar');
    // foo('bar').then(result=>console.log(result));

    Но вообще да, у ноды уже есть fs Promises API
    The fs.promises API provides an alternative set of asynchronous file system methods that return Promise objects rather than using callbacks. The API is accessible via require('fs').promises or require('fs/promises').
    Ответ написан
  • Можно ли из JS передать обработанное изображение в $_FILES?

    @alpeg
    Да, можно.

    var data = new FormData();
    // вариант 1 (если blob был получен из canvas.toBlob(), то он уже будет иметь правильный mime-type)
    data.append("file_field_blob", blob, "filename1.jpg");
    // вариант 2
    data.append("file_field_file_1", new File([blob], "(будет-проигнорировано).jpg", {type:'image/jpeg'}), "filename2.jpg");
    // или так
    data.append("file_field_file_2", new File([blob], "filename3.jpg", {type:'image/jpeg'}));
    var request = new XMLHttpRequest();
    request.onload = function() {
    	if (this.status >= 200 && this.status < 400){
    		document.write(this.response);
    	}
    };
    request.open("POST", "phpinfo.php");
    request.send(data);

    Результат:
    $_SERVER['HTTP_CONTENT_TYPE'] = multipart/form-data; boundary=--...
    $_FILES['file_field_blob'] = Array (
        [name] => filename1.jpg
        [type] => image/jpeg
        [tmp_name] => C:\...\php....tmp
        [error] => 0
        [size] => 46196
    )
    $_FILES['file_field_file_1'] = Array (
        [name] => filename2.jpg
        [type] => image/jpeg
        [tmp_name] => C:\...\php....tmp
        [error] => 0
        [size] => 46196
    )
    $_FILES['file_field_file_2'] = Array (
        [name] => filename3.jpg
        [type] => image/jpeg
        [tmp_name] => C:\...\php....tmp
        [error] => 0
        [size] => 46196
    )

    new File() - https://developer.mozilla.org/en-US/docs/Web/API/F...
    FormData - https://developer.mozilla.org/en-US/docs/Web/API/F...

    Upd:
    Не используйте readAsDataURL! Вместо него надо использовать FileReader.readAsArrayBuffer().
    А если нужна ссылка, например для <img> то нужно создавать её через URL.createObjectURL (и после использования удалять через URL.revokeObjectURL())
    Ответ написан
  • Как в MySQL сделать хитрый join?

    @alpeg
    SELECT `table1`.`username`, `table1`.`dt`, `table1`.`value`, (
    	SELECT `table2`.`value`
    	FROM `table2`
    	WHERE `table1`.`username` = `table2`.`username`
    	ORDER BY ABS(TIMESTAMPDIFF(SECOND, `table1`.`dt`,`table2`.`dt`)) ASC
    	LIMIT 1
    ) AS `t2value`
    FROM `table1`


    Увы, эффективностью тут и не пахнет - EXPLAIN говорит, что в подзапросе будет "Using where; Using temporary; Using filesort" даже с индексами по полям `dt` - т.е. для каждого username из первой таблицы будет выполняться вычисление разницы времени с каждой записью с таким же username из таблицы 2.

    Хотя, если на каждый username в таблице не по 10+ записей, то будет ещё терпимо.

    И, ради бога, используйте вместо table1,table2 нормальный JOIN.
    Ответ написан
    Комментировать