aftamat4ik

Рейтинг
55
Регистрация
05.01.2012
Интересы
php + Drupal
программист недосамоучка

хм. В общем-то советы хорошие. но вся проблема в том что я использую рекурсию и файл нельзя скажем так сразу-же запихнуть в цикл и разобрать по частям(time-limit, именно из-за него и применена рекурсия) Вот код самой функции(это druplal 7)


<?php
$url = "http://test1.ru/somefile.php";//собсна путь к файлу(он на самом деле слегка не так получается у меня)

if(isset($_GET['file_url']) && $_GET['i'] != $_GET["iter"]){//если в файл переданы GET параметры
$file_url = $_GET['file_url'];
$file_name = $_GET['file_name'];
$i = $_GET['i'];

cl_Read($file_url,$file_name.".mp3",512000*$i,512000);//закачиваем файл
$i++;

$ch = curl_init($url."/?file_url=".$file_url."&&iter=".$_GET['iter']."&&i=".$i."&&file_name=".$file_name);//продолжаем рекурсию
curl_setopt($ch, CURLOPT_TIMEOUT, 1);//ожидание ответа сервера - 1 сек. Можно было CURLOPT_TIMEOUT_MS, однако не на всех хостингах последняя версия CURL стоит...
curl_exec ($ch);
curl_close ($ch);
}
if(!isset($_GET['file_url']) && !isset($_GET['i'])){

$file_url = "http://somesite/somefolder/file.mp3";//отсюда качаем

$file_name = './audio/1.mp3';//сюда сохраняем

$fsize = curl_get_file_size($file_url);//получаем размер файла(на удаленном сервере) в килобайтах
$iter = round($fsize/512000) + 1;//число итераций рекурсивного цикла до полной закачки файла частями по 500 килобайт +1 ибо округлению я не доверяю....

cl_Read($file_url,$file_name,0,512000);//первая часть трека. ее мы после загрузки начинаем проигрывать, чтобы пользователя не бесить...

echo $file_name;//передаем урл - ссылку на файл для начала проигрывания, эту ссылку мы получаем в javascript'e и дальше в плеер ее в плеер!

$ch = curl_init($url."/?file_url=".$file_url."&&iter=".$iter."&&i=1&&file_name=".$file_name);//запускаем рекурсию $i = 1, так как первая часть трека уже скачана
curl_setopt($ch, CURLOPT_TIMEOUT, 1);//минимальное ожидание ответа сервера
curl_exec ($ch);
curl_close ($ch);
}

exit();
?>



---------- Добавлено 26.02.2013 в 20:59 ----------

Тут хорошая функция закачки файла блоками - http://stackoverflow.com/questions/6914912/streaming-a-large-file-using-php

Которая тоже не канает из-за рекурсии(

Сам механизм Chunked transfer encoding мне не до конца ясен. Я пытался сделать так(по этому совету - http://stackoverflow.com/questions/13565952/transfer-encoding-chunked-header-in-php-what-is-padding-for):



$url = "http://test1.ru/somefile.php";//собсна путь к файлу(он на самом деле слегка не так получается у меня)

if(isset($_GET['file_url']) && $_GET['i'] != $_GET["iter"]){//если в файл переданы GET параметры
$file_url = $_GET['file_url'];
$file_name = $_GET['file_name'];
$i = $_GET['i'];

cl_Read($file_url,$file_name.".mp3",512000*$i,512000);//закачиваем файл
$i++;

$ch = curl_init($url."/?file_url=".$file_url."&&iter=".$_GET['iter']."&&i=".$i."&&file_name=".$file_name);//продолжаем рекурсию
curl_setopt($ch, CURLOPT_TIMEOUT, 1);//ожидание ответа сервера - 1 сек. Можно было CURLOPT_TIMEOUT_MS, однако не на всех хостингах последняя версия CURL стоит...
curl_exec ($ch);
curl_close ($ch);
}
if(!isset($_GET['file_url']) && !isset($_GET['i'])){

$file_url = "http://somesite/somefolder/file.mp3";//отсюда качаем

$file_name = './audio/1.mp3';//сюда сохраняем

$fsize = curl_get_file_size($file_url);//получаем размер файла(на удаленном сервере) в килобайтах
$iter = round($fsize/512000) + 1;//число итераций рекурсивного цикла до полной закачки файла частями по 500 килобайт +1 ибо округлению я не доверяю....

cl_Read($file_url,$file_name,0,512000);//первая часть трека. ее мы после загрузки начинаем проигрывать, чтобы пользователя не бесить...
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $name);
header('Content-Transfer-Encoding: binary');
header('Content-Encoding', 'chunked');
header('Transfer-Encoding', 'chunked');
header('Content-Type', 'audio/mpeg');
header('Connection', 'keep-alive');


//echo $file_name;//передаем урл - ссылку на файл для начала проигрывания, эту ссылку мы получаем в javascript'e и дальше в плеер ее в плеер!

$ch = curl_init($url."/?file_url=".$file_url."&&iter=".$iter."&&i=1&&file_name=".$file_name);//запускаем рекурсию $i = 1, так как первая часть трека уже скачана
curl_setopt($ch, CURLOPT_TIMEOUT, 1);//минимальное ожидание ответа сервера
curl_exec ($ch);
curl_close ($ch);
}

exit();
?>

После этого при переходе на урл http://test1.ru/somefile.php начиналось скачивание файла и хотя размер файла изменился минимум 2 раза к концу закачки, скачалось всего 500кб. Что я не так делаю то?

Ну не могу я файл разбить на части как здесь(ссылка откуда взят код - выше):


$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}

while (!feof($fp)) {

echo fgets($fp, 128);

}

- не применимо! можно сделать так:

if(!eof($fp)) echo fgets($fp, 128);

но это не приводит к скачке полного файла

И опять-же сокеты мне что-то не по нраву.

В общем как объяснить броузеру что для скачивания следующей части файла надо перейти по такому-то адресу(по тому-же самому) и что передадут с этого адреса прибавить к тому что уже скачано.... ППЦ хД

---------- Добавлено 26.02.2013 в 15:26 ----------

siv1987:
Склеить части задача для школьника, но вопрос в другом, что мешает отдавать в трех "пакетах" по 500К в один файл?

Так так так, а по подробнее)

siv1987:
Что мешает отдавать пользователю непрерывно по 500К без всяких извращений?

и как потом пользователь это все во едино соберет?) допустим будет 3 скачки по 500 килобайт хД) Ну да так то я могу))

Представьте вы скачиваете с сайта 3 части одного! файла и пытаетесь их собрать хДД

Руками))

TF-Studio:
а не проще хостера сменить?
сейчас их как грязи.

Не, не, в хостере дело. Дело в модуле который пишу. Не все же пользователи имеют скажем так безграничные ресурсы на своих хостингах и прочем => значит надо максимально оптимизировать код под среднестатического юзеря, который не хочет портить себе нервы общением с хостером, а хочет просто Результат.

В итоге приходится оптимизировать код под стандартизированный конфиг сервера...

ivan-lev:
Эм.. а точно time_limit не нравится хостингу?

Мне не нравится хД) Я вообще такой изврат стараюсь нигде кроме денвера не применять - не знаю почему, наверное интуиция...

sdaprel:
прописать в файле функцию которая на 29 секунде будет делать get запрос к самой себе и на этом заканчивать свою работу, предварительно записав результат работы в файл tmp, где писать на каком этапе завершил свою работу. При вызове самого себя читает конфиг из тмп и продолжает качать дальше. Как так, думаю можно реализовать данную задачу

На самом деле я и планировал сделать примерно это, просто вышеуказанный кусок кода доказал свою работоспособность и я не заморачиваюсь теперь хД

Точно! сча попробую)

---------- Добавлено 25.02.2013 в 15:52 ----------

РАБОТАЕТ!!! Урааа)

Тестил вот этим:


single_rec(0);
echo "sucess";

function single_rec($i){
if($i<5){
sleep(20);
return single_rec($i+1);
}else return 0;
}


---------- Добавлено 25.02.2013 в 15:54 ----------

Есть у подобного подхода "подводные камни"?

Всем спасибо, уже написал хД Скоро буду рекурсию организовывать и прочие блага. Кому интересно писал по одкопанному где-то в глубинах гугла куску кода:

ссылка - http://marc.info/?l=php-general&m=117244455625774

Прошу прощения. Все вкурил тему)

Помогите плз. Пишу батч, такого вида:


function my_function_2(&$context) {
$data = object_from_file(drupal_get_path('module', 'rmodule') . "/includes/data/authors.txt");
if (empty($context['sandbox'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['max'] = count($data);
}
$limit = 1;
if(empty($context['sandbox']['items'])) {
$context['sandbox']['items'] = $data;//чо-то типа жизнь проходит мимо...(Витя Ак)
}


// Убираем из массива с данными уже обработанные материалы

$counter = 0;

foreach ($context['sandbox']['items'] as $item) {
sleep(1);//чтобы быстро не мотало
$file_patch = drupal_get_path('module', 'rmodule') . "/" . $item['img_url'];
$file = (object) array(
'uid' => 1,
'status' => 1
);
$file->filename = basename($file_patch);
$file->uri = $file_patch;
//file_copy($file,"public://");

go_something($file);
//$context['results'][] = $file_patch . ' : ' . $item['title'];

$counter++;
$context['sandbox']['progress']++;
$context['message'] = $item['title'];
$context['results']['processed'] = $context['sandbox']['progress'];
}
if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
$context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
}
}

И вот что вылазит

An AJAX HTTP error occurred. HTTP Result Code: 200 Debugging information follows. Path: /batch?id=108&op=do StatusText: OK ResponseText: Fatal error: Maximum execution time of 90 seconds exceeded in Z:\home\test1.ru\www\sites\all\modules\rmodule\includes\add_data.batch.inc on line 21

Вроде бы батч он на то и батч чтобы обходить Maximum execution time и прочую ерунду. Что делать? может я где-то не верно в коде написал?

big boy, http://drupalace.ru/lesson/obrabotka-bolshogo-kolichestva-dannyh-s-pomoshchyu-batch-api

Почитайте, как раз про изменение заголовка в нодах... Хотя это думаю слишком замудрено для такой задачи.

big boy, Если у вас пункт меню делается через хук hook_menu, то так можно присвоить кастомный заголовок к созданному пункту:


function mymodyle_menu() {
$items = array();
$items['custom_manu'] = array(//ваш пункт меню
'title' => t('Бла бла бла'),//это не надо
'title callback' => 'mymodule_title',//тут делаем заголовок
'type' => MENU_CALLBACK,
'page callback' => 'кэллбэк функция',
'access arguments' => array('access content'),
);
return $items;
}
function mymodule_title(){/*Задаем тайтл для страницы поиска, ибо СЕО хД*/

return t("Новый титле");
}

Тут можно сделать так(у меня так)


function rmodule_audio_title(){/*Задаем тайтл для страницы поиска, ибо СЕО хД*/
if(strlen(arg(1))!=0){
return t("Поиск музыки по запросу:".arg(1));
}else
return t("Фраза не найдена");
}

Что хороше для сео. Если у вас к нодам отдельного типа надо прикрутить кастом ный заголовок то мы в одной тарелке, ибо так(хук node_view):

$node->content['body']['#object']->title = "Бла блы бла!";

Не хочет менять. Примерно то-же самое что и у меня, только с картинками.

---------- Добавлено 08.02.2013 в 06:00 ----------

Попробуйте hook_node_view_alter(&$call)

Тут можно вроде в массиве копнуть $call - там по любому есть

К слову - с картинками пытался так сделать - не катит. Хотя может мне просто взять и сделать так(говнокод детектед)


$tmp = implode(';',$call);
str_replace(и поменть все элементы в которых встречается /sites/default/files/)
$call = array();//обнулим
$call = explode($tmp,";");


---------- Добавлено 08.02.2013 в 06:01 ----------

_________________________

Сидя в бронированном танке танкисты нервно курили....

Всего: 143