Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 04.02.2025, 17:23   #11
DeepFlake
Форумчанин
 
Регистрация: 16.05.2024
Сообщений: 143
По умолчанию

Цитата:
А как тогда следующий пользователь сможет его скачать?
Задавать время жизни ссылки. То есть удалять только после истечения срока действия.

Цитата:
два текстовых файла со списками, один с реальными урл, второй с подставными и сроком действия.
Одну таблицу просто разбили на две. Это ничего не меняет принципиально.

Цитата:
Я так понимаю, что в момент обращения за скачиванием юзер получает свежесгенеренную ссылку (тупой случайный набор), которая соотносится с реальным адресом по ID, который одинаковый у данного файла в обеих таблицах. И в этот же момент подставной адрес и срок заносятся во вторую таблицу.
А как пользователь обратится по ссылке за файлом, если он эту ссылку ещё не знает?
Вся эта белиберда с подставными ссылками делается как раз чтобы никто не смог скачать файл, а скачать мог только тот, кто заранее знает подставное (длинное из случайных символов) имя (ссылку). Иначе какой смысл?

То есть подставное имя (ссылку) надо заранее сгенерировать и дать нужному пользователю (только ему одному). И при этом это имя заносится в соответствующую таблицу на сервере.

Цитата:
Сам подставной адрес нужен только для того, чтобы опознавать юзера
Обычно не так. Подставной адрес - чтобы никто другой не смог скачать этот файл. Пользователь никак не опознаётся по ссылке. Если этот пользователь даст другому пользователю подставную ссылку, то тот тоже сможет скачать.

Цитата:
я думала, они как-то хитро зашифровываются, что ссылка уже содержит адрес файла и срок годности.
Вообще, это хорошая идея для генерации случайного и неповторяющегося имени, только для вычисления дайджеста надо включать ещё какой-то секретный ключ (кусок информации, который никто не знает).
DeepFlake вне форума Ответить с цитированием
Старый 04.02.2025, 17:43   #12
DeepFlake
Форумчанин
 
Регистрация: 16.05.2024
Сообщений: 143
По умолчанию

Цитата:
Не знаю еще, как отдавать файл посредством php, но попробую разобраться.
может так?:
Код:
<?php
   echo file_get_contents( "myfile.zip" );
?>
DeepFlake вне форума Ответить с цитированием
Старый 05.02.2025, 09:01   #13
pu4koff
Старожил
 
Аватар для pu4koff
 
Регистрация: 22.05.2007
Сообщений: 9,097
По умолчанию

Цитата:
Сообщение от Romeo4755 Посмотреть сообщение
Я нашла словесное описание, кот более-менее прояснило процедуру - два текстовых файла со списками, один с реальными урл, второй с подставными и сроком действия.
Файлы со списками я бы в принципе не делал, т.к. нужно синхронизировать доступ и т.п.
Настоящие файлы, например, класть в папку files. В папку links записывать файлы-описатели подставных ссылок. Допустим, нужно загрузить на сайт новый файл "документ.txt". Кладём его по ftp в папку files. Так же создаём для него, например, json файл вида:
Код:
{
  "path": "документ.txt",
  "expiration": "2025-02-06"
}
и кладём его в папку links под именем gfdgfdgd.
Когда пользователь обращается по адресу: www.mysite.ru/gfdgfdgd
сервер на php лезет в папку links, читает файл gfdgfdgd, смотрит какой реальный файл нужно отдать, не истёк ли срок действия ссылки, тот ли пользователь грузит его и что там нужно ещё проверять. Если всё нормально, то возвращает содержимое файла "документ.txt" из папки files.
Цитата:
Сообщение от Romeo4755 Посмотреть сообщение
Я так понимаю, что в момент обращения за скачиванием юзер получает свежесгенеренную ссылку (тупой случайный набор), которая соотносится с реальным адресом по ID, который одинаковый у данного файла в обеих таблицах. И в этот же момент подставной адрес и срок заносятся во вторую таблицу.
Зависит от целей, чего хочется получить и что вообще делаете.
Можно сделать так, что пользователь по ссылке обращается условно изначально к настоящему файлу: www.mysite.ru/документ.txt
только сервер не отдаёт ему сам файл, а показывает страницу с рекламой. Досмотрел рекламу - сервер генерирует сам файлик для подменной ссылки под этот файл с нужным сроком действия и делает redirect уже на www.mysite.ru/gfdgfdgd
Цитата:
Сообщение от Romeo4755 Посмотреть сообщение
А я думала, они как-то хитро зашифровываются, что ссылка уже содержит адрес файла и срок годности.
Ну, можно на сервере ничего не хранить, кроме самих файлов. Указанный выше вариант json'а шифровать, кодировать в base64 и т.д. и отдавать пользователю в качестве ссылки. При обработке запроса соответственно назад расшифровывать и определять какой файл нужно отдать. Но, если кто-то расшифрует такую ссылку, то сможет сам генерировать ссылки и запрашивать нужные ему файлы.
pu4koff вне форума Ответить с цитированием
Старый 05.02.2025, 11:55   #14
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 15,736
По умолчанию

Цитата:
Сообщение от DeepFlake Посмотреть сообщение
echo file_get_contents( "myfile.zip" );
Тут надо отметить, что file_get_contents читает содержимого файла в память, а далее отдаем его в поток вывода с помощью echo. Подводный камень такого метода: если файл большой, можно не пройти по ограничению на использование памяти.

Более универсальный способ это сначала выяснить размер файла, определить ограничение по памяти, далее читать файл кусками и отдавать тоже кусками. Причем размер куска не должен быть равен ограничению по памяти (так как память будет занята и прочими данными). Можно условно взять половину от ограничения.

Хотя в каждом индивидуальном случае надо смотреть на расход памяти. Скажем, ТС указала, что список файлов и хешей хранятся в другом файле, а значит для их сопоставления тот файл тоже должен быть прочитан в память, после чего нужно будет найти реальное имя файла по его хешу. Это все тоже расходует оперативную память.
Arigato вне форума Ответить с цитированием
Старый 05.02.2025, 13:32   #15
DeepFlake
Форумчанин
 
Регистрация: 16.05.2024
Сообщений: 143
По умолчанию

to Arigato:
file_get_contents реализован через mmap. Но, конечно, надо поэкспериментировать с большими файлами. Там ещё надо будет правильный content type указывать через @header()
DeepFlake вне форума Ответить с цитированием
Старый 05.02.2025, 15:14   #16
Arigato
Высокая репутация
СуперМодератор
 
Аватар для Arigato
 
Регистрация: 27.07.2008
Сообщений: 15,736
По умолчанию

Цитата:
Сообщение от DeepFlake Посмотреть сообщение
надо поэкспериментировать с большими файлами
Проверил. Вот такой код для проверки:
Код:
<?php

download('1.zip');

// Функция отправит файл пользователю для загрузки
function download($filename){
	$length = filesize($filename);
	if ($length === false) return false;
	header("Content-Type: application/octet-stream");
	header("Content-Length: $length");
	header('Content-Disposition: attachment; filename="' . rawurlencode(basename($filename)) . '"');
	echo file_get_contents($filename);
	return true;
}
Файл 1.zip у меня 17 Мб, в настройках php.ini установил лимит в 10 Мб: memory_limit=10M

По итогу в скаченный 1.zip попадает сообщение об ошибке:

Код:
<br />
<b>Fatal error</b>:  Allowed memory size of 10485760 bytes exhausted (tried to allocate 18178800 bytes) in <b>D:\WWW\download\index.php</b> on line <b>12</b><br />
Естественно, никакого оригинального файла загрузить не удалось.

Так что либо ставить жесткий лимит на размер файла, если файл больше, то выдавать в браузер сообщение о том, что такой файл не может быть скачен. Либо отдавать файл кусками.

Но приведенная мною функция download($filename) полностью рабочая, если размер файла проходит по лимитам памяти. Возможно, для ТС она подойдет, если у него файлы маленькие.
Arigato вне форума Ответить с цитированием
Старый 06.02.2025, 13:48   #17
DeepFlake
Форумчанин
 
Регистрация: 16.05.2024
Сообщений: 143
По умолчанию

Посмотрел исходный текст file_get_contents(), да она создаёт буфер в памяти:
Код:
/* {{{ Read the entire file into a string */
PHP_FUNCTION(file_get_contents)
{
   .....

	if ((contents = php_stream_copy_to_mem(stream, maxlen, 0)) != NULL) {
		RETVAL_STR(contents);
	} else {
		RETVAL_EMPTY_STRING();
	}

	php_stream_close(stream);
}
/* }}} */
Здесь php_stream_copy_to_mem() создаёт буфер.

Но нашёл другую функцию, readfile(), и это, кажется, то что нужно.
В документации про неё написано:
"readfile() сама по себе не приводит к каким-либо проблемам с памятью, даже при отправке больших файлов. При возникновении ошибки превышения памяти убедитесь, что буферизация вывода отключена с помощью ob_get_level()."
Хотя это несколько странно, ведь ob_get_level() не отключает буфер, а отключает ob_end_flush().
Там вот пример такой:
Код:
<?php
$file = 'monkey.gif';

if (file_exists($file)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($file));
    readfile($file);
    exit;
}
?>
Вот исходный текст readfile():
Код:
/* {{{ Output a file or a URL */
PHP_FUNCTION(readfile)
{
	char *filename;
	size_t filename_len;
	size_t size = 0;
	bool use_include_path = 0;
	zval *zcontext = NULL;
	php_stream *stream;
	php_stream_context *context = NULL;

	ZEND_PARSE_PARAMETERS_START(1, 3)
		Z_PARAM_PATH(filename, filename_len)
		Z_PARAM_OPTIONAL
		Z_PARAM_BOOL(use_include_path)
		Z_PARAM_RESOURCE_OR_NULL(zcontext)
	ZEND_PARSE_PARAMETERS_END();

	context = php_stream_context_from_zval(zcontext, 0);

	stream = php_stream_open_wrapper_ex(filename, "rb", (use_include_path ? USE_PATH : 0) | REPORT_ERRORS, NULL, context);
	if (stream) {
		size = php_stream_passthru(stream);
		php_stream_close(stream);
		RETURN_LONG(size);
	}

	RETURN_FALSE;
}
/* }}} */
Тут php_stream_passthru() как раз выводит без буферизации (если отключено).

Вроде как можно ещё функцией fpassthru() вывести файл за раз:
Код:
<?php

// открываем файл в бинарном режиме
$name = './img/ok.png';
$fp = fopen($name, 'rb');

// отправляем нужные заголовки
header("Content-Type: image/png");
header("Content-Length: " . filesize($name));

// сбрасываем картинку и останавливаем выполнение скрипта
fpassthru($fp);
exit;

?>

Последний раз редактировалось DeepFlake; 06.02.2025 в 13:51.
DeepFlake вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
ссылка на файл в sql mchip Microsoft Office Excel 5 23.03.2016 14:21
Ссылка на файл Апчхи Microsoft Office Excel 24 16.11.2013 01:34
Не получается ссылка на IMG As_Pushkin HTML и CSS 2 15.06.2010 21:54
Ссылка на файл из текущей папки! Сбор инфы в один файл! mephist Microsoft Office Excel 11 10.07.2009 13:51
массы n идентичных на вид монет среди которых одна фальшивая - легче или тяжелее остальных Wintrymoon Паскаль, Turbo Pascal, PascalABC.NET 14 10.03.2008 23:10