На сервере есть файл 'ip.txt', записи имеют примерно такой вид: 11.11.11.11 = 3 44.44.44.44 = 1 88.88.88.88 = 1 Как сделать, чтобы искался ip из переменной $ip и если он найден прибавлять после знака = +1, то есть если $ip = 44.44.44.44, то 44.44.44.44 = 2 (было 44.44.44.44 = 1)
Код (Text): <?php /* //открываем файл, и сохраним его содержимое в переменной //сначала разбив на ip и его значение, которое идет после // получим такого вида массив: * array(3) { [0]=> array(2) { [0]=> string(12) "11.11.11.11 " [1]=> string(3) "3 " } [1]=> array(2) { [0]=> string(12) "44.44.44.44 " [1]=> string(2) "1 " } [2]=> array(2) { [0]=> string(12) "88.88.88.88 " [1]=> string(3) "1 " } } * * пример чтения файла взять из документации php.net с последюющим незначительными * правками * http://php.ru/manual/function.fgets.html */ $handle = @fopen("ip.txt", "r"); //получим файловый указатель. $i = 0; if (flock($handle, LOCK_EX)) { // выполняем эксклюзивную блокировку ftruncate($handle, 0); // очищаем файл if ($handle) { while (($buffer = fgets($handle)) !== false) { $ip_data[] = explode("=", $buffer); $i++; } if (!feof($handle)) { echo "Error: unexpected fgets() fail\n"; } fflush($handle); // очищаем вывод перед отменой блокировки flock($handle, LOCK_UN); // отпираем файл fclose($handle);//закрываем открыйтый дескриптор файла } } //отладка echo "<pre>"; var_dump($ip_data); echo "</pre>"; /* * теперь имея массив с данными из файла, мы можем сравнивать IP-адреса с * IP-адресом из переменной $ip * * */ //пусть $ip = "88.88.88.88"; $ip = "88.88.88.88"; $to_write; for ($j = 0; $j < count($ip_data); $j++) { if (strcmp($ip, trim($ip_data[$j][0])) === 0) { echo $new_value = trim($ip_data[$j][1]) + 1; $to_write .=$ip_data[$j][0] . "=" . $new_value . "\r\n"; } else { $to_write .=$ip_data[$j][0] . "=" . trim($ip_data[$j][1]) . "\r\n"; } } //отладка echo "<pre>"; var_dump($to_write); echo "</pre>"; /* * Теперь, сохраним изменения в файле * * Этот код тоже взять из документации * с незначительными изменениями. * http://php.ru/manual/function.fwrite.html */ $filename = "ip.txt"; // Вначале давайте убедимся, что файл существует и доступен для записи. if (is_writable($filename)) { //Открывает файл только для записи; помещает указатель в начало файла и //обрезает файл до нулевой длины. Если файл не существует - пробует его создать. if (!$handle = fopen($filename, 'w')) { echo "Не могу открыть файл ($filename)"; exit; } if (flock($handle, LOCK_EX)) { // выполняем эксклюзивную блокировку ftruncate($handle, 0); // очищаем файл // Записываем $to_write в наш открытый файл. if (fwrite($handle, $to_write) === FALSE) { echo "Не могу произвести запись в файл ($filename)"; exit; } echo "Ура! Записали ($somecontent) в файл ($filename)"; fflush($handle); // очищаем вывод перед отменой блокировки flock($handle, LOCK_UN); // отпираем файл fclose($handle);//закрываем открыйтый дескриптор файла } else { echo "Файл $filename недоступен для записи"; } } unset($handle);
если ты про то что denis01 уже проделал такое, и я выложил, то выложил потому что уже написал. Вариант denis01 мне больше нравится. Добавлено спустя 2 минуты 1 секунду: ??
ты только что продемонстрировал какой ты специалист. никакой. если не знаком с термином можно втихую пойти погуглить. в задании не сказано что обращение к скрипту будет исключительно одно монопольное. следовательно не исключена вероятность одновременного обращения к обрабатываемому файлу. и как следствие скрипты находясь в состоянии гонки приведут к потере целостности данных - стату запишет тот скрипт который записывает последним. переписав потуги того который начался первым. я как бы не стал публично критиковать то что ты называешь кодом и просто сразу указал на ту проблему которую ты вообще не учел. состояние гонки. учи матчасть.
Спасибо! Но мне больше понравился первый вариант, все работает, но числа не прибавляются, прибавляется только 1, а потом 2, 3 и.д - нет Код (Text): <?php $usnum = array(); $num = file('settings.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); $out = ''; foreach (file('settings.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $key => $value) { $x = explode('=', $value); if($x) { if(in_array($x[0], $num)) { $x[1] = trim($x[1]) + 1; } $usnum[$x[0]] = $x[1]; $out = $out.PHP_EOL.$x[0].'='.$x[1]; } } file_put_contents('settings.txt', ltrim($out)); ?>
не додумался, и спасибо, уже есть чт-то новое.. состояние гонки. я только за критику О блокировке я подумал , но куда-то улетучилась эта мысль по ходу копирования и вставки кода. Отредактировал свое первое сообщение. Добавлено спустя 3 минуты 24 секунды: это еще какой -то термин*?
ох зря... стало только хуже... ладно, вы пока посоревнуйтесь разными алгоритмами а я вечерком накатаю свою версию. Добавлено спустя 12 минут 27 секунд: перед прогулкой решил таки бенчмарк своей идеи и твоего кода устроить. 1000 проходов по фиксированно произвольному массиву в 120 "айпишников". файл данных на рамдрайве дабы йопы не сильно влияли. Код (Text): ru_php_forum_52305_GANZAL_01 : 6.430408 ru_php_forum_52305_GANZAL_02 : 8.444232 ru_php_forum_52305_mahmuzar_01 : 15.105814 ru_php_forum_52305_mahmuzar_02 : 16.030584 корректность твоего алгоритма не отлаживал. допустим он дает такие же корректные данные как и мой.
вижу разница огромная хотел бы увидеть твой вариант я еще раз отредактировал свой вариант. Код (Text): //откроем файл для чтения и записи $fp = fopen("ip.txt", 'r+') or die("не удалось прочесть файл"); //пусть $ip = "132.154.226.1"; $ip = "132.154.226.1"; if (flock($fp, LOCK_EX)) { // выполняем эксклюзивную блокировку while (($line = fgets($fp)) !== false) { //$line - это прочтенная строка из файла $ip_from_file = trim(strstr($line, '=', TRUE));//получим из строки ip $ip_value = trim(substr($line, strrpos($line, '=') + 1));//получим значение ip if (strcmp($ip, $ip_from_file) === 0) { $to_write .= $ip_from_file . "=" . sprintf($ip_value + 1) . "\r\n"; } else { $to_write .=$ip_from_file . "=" . $ip_value . "\r\n"; } } fseek($fp, 0);//переместим указатель в начало файла ftruncate($fp, 0); // очищаем файл // // Записываем $to_write в наш открытый файл. if (fwrite($fp, $to_write) === FALSE) { echo "Не могу произвести запись в файл"; exit; } fflush($fp); // очищаем вывод перед отменой блокировки fclose($fp); //закрываем открытый дескриптор файла } что насчет варианта denis01?
ты делаешь очень много действий бесполезных. ща твой кодец к себе в бенчмарк портирую да расскажу в чем ты не прав. Добавлено спустя 22 минуты 13 секунд: такой ты жоский)))) смари. вот этот вот код который прям перед этим моим постом: Код (Text): ru_php_forum_52305_mahmuzar_03 : 8.850873 с улыбкой удаляю 67 МЕГАБАЙТ ВОРНИНГОВ, ставлю сабаки перед переменными которые ты инициализируешь где-то во сне и запускаю повторно Код (Text): ru_php_forum_52305_mahmuzar_03 : 6.473487 отличный результат. но абсолютно бесполезный потому что результат накидывания тестового набора айпишников не соответствует эталонному. Парам парам пам, фшшшшшшыыыть, ПАМ!
Тут как бы с точки производительности в глаза бросается 2 момента 1. Дать поиск нужного ip с строкой нужно до расчленения строки на ip и значение. Тем самым убираем несколько лишних действий. 2. Зачем делать какие то конкатенации когда есть нужная не измененная целая строка в $line?
Да ну, влом как то, можно еще строчку Код (PHP): $ip_value = trim(substr($line, strrpos($line, '=') + 1));//получим значение ip с 3 функций сократить до 1 Код (PHP): $value = explode(" = ", $line)[1]; Мы же знаем что перед и после равно есть пробел, формат записи строки не должен меняться. Искомый ip имеется нам не надо создавать переменную для ее хранения.
при обнаружении $ip можно далее не продолжать конкатенацию. Как же так, у меня ворнинга не было нигде. А какие были правки?) вроде все инициализировано
работает как написан) Я имею в виду подумывал о том же, что ты говоришь. Можно было бы не продолжать конкатенацию, после того, как находится совпадение ip
if (strcmp($ip, $ip_from_file) === 0) { @$to_write .= $ip_from_file . "=" . sprintf($ip_value + 1) . "\r\n"; } else { @$to_write .=$ip_from_file . "=" . $ip_value . "\r\n"; } вот такая была правка. потому что ты конкатенируешь но переменная не объявлена. высыпается ворнинг. а поскольку у меня это всё дело обернуто в метод который вызывается для каждого из 123 (да, теперь 123) айпишников из пакета и тысячу прогонов то получаем 123000 (сто двадцать три тысячи) ворнингов за тест. фу-фу-фу.
Забавно. А почему у меня нету воргнинга? Добавлено спустя 3 минуты 47 секунд: Код (Text): Notice: Undefined variable: to_write in C:\server\www\tester\call.php on line 25 error_reporting = E_ALL & ~E_NOTICE предупреждения у меня были в игноре, поэтому не высвечивались)) Добавлено спустя 5 минут 57 секунд: когда ты сказал про ворниг, я реально подумал про ворнинг. учту, что и это дело сказывается на производительности. Спасибо, было позновательно. а что насчет этого подхода? Добавлено спустя 14 минут 44 секунды: эту строку можно сменить этой Код (Text): $to_write .=$line;
А как будет такой вариант? Код (PHP): <?php error_reporting(E_ALL); $ip=getenv('REMOTE_ADDR'); $f='ip.txt'; if(strpos(file_get_contents($f), $ip)===false){file_put_contents($f, "$ip=1\r\n", FILE_APPEND); } else{ $ar=file($f); foreach ($ar as $k=>$v) { if(strpos($v, $ip) !==false) { $sub=substr($v, strlen($ip)+1); $ar[$k]=$ip.'='.($sub+1)."\r\n"; file_put_contents($f, $ar); break; } } } просто интересно...
ща у меня самый толстый тест пролетит и этот код попробую. но уже видно что идет двойное чтение файла.
Добавлено спустя 3 минуты 43 секунды: Вызывают некоторые сомнения строчка Код (PHP): file_put_contents($f, $ar); но лень есть лень, запускать твой код не буду поэтому это останется моей догадкой