Отладка скриптов вообще дело крайне нужное и полезное. Кроме основной задачи — поиска и удаления ошибок, отладка прямо улучшает качество и работоспособность программы в целом. Выловленные баги, исправленная логика — все это делает программу стабильнее в работе, что весьма желанная цель при ее написании. Все ниженаписанное основывается на моем опыте, так что воспринимайте это как мое имхо ))
Archive for the ‘Скрипты’ Category
Вложенные SQL запросы: одновременное добавление одинарных и множественных строк в INSERT
Понадобилось для одной задачи сделать выборку из таблицы А по определенным условиям и вставить ее в таблицу B.
Можно особо не заморачиваться, сделать SELECT в переменную, потом пройтись циклом по INSERT и все.
Но это не очень красивое решение. Очень запросов много + на переменные память расходуется. Проще использовать вложенные запросы, они же nested queries. Но тут возникает проблемка — если вставлять только данные из INSERT, то все ок, но если добавлять еще и какие-нибудь неизменные значения, то выдается Subquery returned more than 1 value.
Чтобы не обьяснять на пальцах — сама таблица B
CREATE TEMPORARY TABLE `B` ( `status` TINYINT(4) NULL DEFAULT NULL , `pair` TEXT NULL DEFAULT NULL , ) ENGINE = MyISAM DEFAULT CHARACTER SET = utf8 COLLATE = utf8_general_ci;
Копируем из таблицы A и вставляем в B так
INSERT INTO `B` (`pair`) SELECT `pair` FROM `A` ORDER BY RAND() LIMIT 100;
Если поле status имеет неизменное значение, например 123, то просто вот так уже не вставить
INSERT INTO `B` (`status`, `pair`) VALUES ( (SELECT `pair` FROM `A` ORDER BY RAND() LIMIT 100), 123);
Не совсем красивое решение нашел
UPDATE `B` SET `status` = '123' WHERE 1=1;
Но хотелось бы в одну строку все заделать. Отпишитесь плиз в коментах, кто знает, как реализовать.
Класс для работы с сервисами сокращения ссылок
Небольшой класс, возвращает сокращенную ссылку. Можно обращаться как напрямую к конкретному сервису, так и выбранному рандомно через Shorteners->any(). Есть возможность указать прокси.
Работает с
- bit.ly
- goo.gl
- is.gd
- tinyurl.com
- dlmn.org
- ndurl.com
- qr.cx
- gatorurl.com
- jmb.tw
- linkee.com
- mtny.mobi
- cli.gs
<?php error_reporting(1); class Shorteners { public $proxy = null; public function bitly($url) { $connectURL = 'http://api.bit.ly/v3/shorten?login=masstest&apiKey=R_44403eb439622dd59ba2598255f30824&uri=' . urlencode($url) . '&format=txt'; return $this->curl_get_result($connectURL, NULL); } public function googl($url) { $connectURL = 'http://goo.gl/api/shorten'; $post_fields = "security_token=null&url=" . urlencode($url); $res = $this->curl_get_result($connectURL, $post_fields); $obj = json_decode($res); $ans = (!empty($res)) ? $obj->{'short_url'} : false; return $ans; } public function isgd($url) { $connectURL = 'http://is.gd/api.php?longurl=' . urlencode($url); return $this->curl_get_result($connectURL, NULL); } public function tinyurl($url) { $connectURL = 'http://tinyurl.com/api-create.php?url=' . urlencode($url); return $this->curl_get_result($connectURL, NULL); } public function dlmn($url) { $connectURL = 'http://dlmn.org/submit/?url=' . urlencode($url) . '&ajax=false'; $page = $this->curl_get_result($connectURL, NULL); preg_match("/<input id=\"dlmn-loc\" value=\"(.*?)\"/si", $page, $out); if (strlen($out[1]) < 3) { return false; } else { $answer = (empty($out[1])) ? false : "http://" . $out[1]; return $answer; } } public function crum($url) { $connectURL = 'http://crum.bs/api.php?function=simpleshorten&url=' . urlencode($url); return $this->curl_get_result($connectURL, NULL); } public function ndurl($url) { $connectURL = 'http://www.ndurl.com/api.generate/?url=' . urlencode($url) . '&type=web'; $res = $this->curl_get_result($connectURL, NULL); $obj = json_decode(stripslashes($res)); $obj = $obj->data; $ans = (!empty($res)) ? $obj->{'shortURL'} : false; return $ans; } public function qr($url) { $connectURL = 'http://qr.cx/api/?longurl=' . urlencode($url); return $this->curl_get_result($connectURL, NULL); } public function gatorurl($url) { $connectURL = 'http://gatorurl.com/api/rest.php?url=' . urlencode($url); return $this->curl_get_result($connectURL, NULL); } public function jmb($url) { $connectURL = 'http://jmb.tw/api/create/?newurl=' . urlencode($url); return $this->curl_get_result($connectURL, NULL); } public function linkee($url) { $connectURL = 'http://api.linkee.com/1.0/shorten?input=' . urlencode($url); $res = $this->curl_get_result($connectURL, NULL); $obj = json_decode($res); $ans = (!empty($res)) ? $obj->{'result'} : false; return $ans; } public function mtny($url) { $connectURL = 'http://mtny.mobi/api/?url=' . urlencode($url) . '&ismobile=false&type=simple'; return $this->curl_get_result($connectURL, NULL); } public function cligs($url) { $connectURL = 'http://cli.gs/cligs/new'; $post = "URL=" . urlencode($url); $page = $this->curl_get_result($connectURL, $post); preg_match("/Your new clig has been created/si", $page, $out); if (strlen($out[0]) < 3) { return false; } else { preg_match("#http://twitter.com/home\?status=(.*?)\"#si", $page, $out); $answer = (empty($out[1])) ? false : $out[1]; return $answer; } } public function any($url) { $func = get_class_methods($this); $sh = $func[array_rand($func, 1)]; return $this->$sh($url, NULL); } private function curl_get_result($url, $postdata) { $ch = curl_init(); $timeout = 5; curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); if (isset($postdata)) { curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); } if ($this->proxy) { //var_dump( $this->proxy ); curl_setopt($ch, CURLOPT_PROXY, $this->proxy); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, "60"); curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5); curl_setopt($ch, CURLOPT_TIMEOUT, "60"); } else { curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, "30"); curl_setopt($ch, CURLOPT_TIMEOUT, "30"); } $data = curl_exec($ch); curl_close($ch); return trim($data); } } $test = new Shorteners(); $url = "http://rambler.ru"; $class_methods = get_class_methods('Shorteners'); foreach ($class_methods as $method): echo $test->$method . "\r\n"; endforeach; ?>
Простой способ проверки процесса на существование
Для простых многопоточных систем очень часто используют запуск в фоновом режиме. Запускают их примерно вот так:
php script.php &
И управление процессом от юзера уходит, отловить такой процесс из другого скрипта уже не получится. А если процесс выполняет какую то одну и ту же задачу с интервалом по крону, и нужно, чтобы при запуска нового процесса старый был убит? Поймать его можно аццкой смесью bash + php:
$killPid = exec("ps ux | awk '/script_name.php/ && !/awk/ {print $2}'");//находим пид процесса if($killPid)//если есть, киляем exec ("kill ".$killPid); exec('php script_name.php &');//запускаем новый
Примеры использования strace для отладки скриптов
Strace — это встроенный перехватчик системных вызовов и сигналов в линуксе. Основная его цель — это перехват информации относительно какого-то процесса. Крайне незаменимая штука при отладке скриптов, особенно закодированных.
Пример использования — есть один сервис, который я написал, и обьявилась там проблема — каким-то неведомым образом права на файл, куда пишется лог, начали выставляться криво. А именно: вместо положенных rw — rw — rw стали w — wx — wT. Проблема тут в том, что надо указывать права при смене не как:
chmod('file.txt', '0666'); или chmod('file.txt', 666);
в этом случае 0666 будет string, а вот так:
chmod('file.txt', intval('666', 8));
Так они уже будут в корректной форме.
Вернемся к проблеме. Нужно было найти, кто ставит на файл неверные права. Вот так можно отловить все вызовы определенного файла:
strace php ./script.php 2>&1 | grep file.txt
Ответ будет вида:
open("/path/to/file.txt", O_RDWR|O_CREAT|O_APPEND|O_LARGEFILE, 0666) = 4 chmod("/path/to/file.txt", 0666) = 0
Вот так можно отмониторить все обращения к файлу
Read On…
Размножение строк — функция генерации всех возможных значений из шаблона {}
Понадобилась такая функция, решил размять мозги. Функция понимает в качестве разделителя запятые, |, ;. Вызов показан в конце.
<?php function mashUp($str){ preg_match_all("/{(.*?)}/", $str, $out); $headArr = $out[1]; for($i = 0; $i < sizeof($headArr); $i++) { $valArr = preg_split("/(\||,|;| )/", $headArr[$i]); ($i == 0)? $sTotal = count($valArr) : $sTotal = $sTotal * count($valArr); $varr[] = $valArr; } for($i = 0; $i < $sTotal; $i++){ $strings[$i] = $str; } foreach($headArr as $num => $val): $currPos = 0; //позиция ключа в $varr for($i = 0; $i < $sTotal; $i++) { if($i == 0): if($num == 0) { $sChange = ( $sTotal / ( count($varr[$num]) ) ); } else { ($old)? $sChange = $old : $sChange = $sChange; $sChange = ($sChange / (count($varr[$num]))); } if(count($varr[$num]) < 2){ $old = $sChange; $sChange = $sTotal; } if($num == (count($headArr) - 1)) { $sChange = 1; } $sNum = $sChange; endif; if($sNum == 0){ $sNum = $sChange - 1; $currPos++; } else { $sNum--; //$currPos++; } if($currPos > (count($varr[$num]) - 1)) $currPos = 0; preg_match("/{(.*?)}/", $strings[$i], $res, PREG_OFFSET_CAPTURE, 0); $strings[$i] = preg_replace("!".preg_quote($res[0][0])."!si", $varr[$num][$currPos], $strings[$i]); } endforeach; return($strings); } $str = "some {1a|2a,3a;4a 5a} strings {1b|2b|3b} that {1c} need to {1d|2d} post {test|example|primer}"; echo maashUp($str); ?>
MYSQL RAND(), как получить рандомную строку из БД
Чем дольше занимаюсь кодингом, тем чаще втыкаюсь в такие вещи, которые сто раз уже использовал, а на 101 сломал голову.
Есть таблица, в ней N тысяч записей, нужно вытащить одну рандомно, кой-чего с ней сделать, и если все ок то ее использовать, если нет то вернуть на место с соответствующей отметкой и взять другую, пока не будет найдена подходящая по условиям.
Я, особо не мудря, делаю цикл while до условия, пока не найдена подходящая запись. В цикле такой запрос к БД
SELECT * FROM `table` WHERE 1 ORDER BY RAND() LIMIT 1
По задумке, это возвращает каждый раз новую запись. Но у mysql есть такая приятная особенность — она кеширует запросы и в цикле каждый будет возвращаться одно и тоже поле. Наверно, если разрывать соединение, тогда будет возвращаться разное число. Я таких вещей в душе не знал, поэтому немного удивился, погуглив, что это самый дибильный способ вытащить рандомную запись из базы. На очень больших БД это завесит сервер напрочь.
Вариант получше заключался в том, чтобы вытащить максимальное значение записей и получить рандомное число в его пределах, затем запросить из базы строку с LIMIT рандомное число.
//запрос макс количества записей в переменную SELECT FLOOR(RAND() * COUNT(*)) AS `offset` FROM `table` //далее запрос с этой переменной SELECT * FROM `table` LIMIT $somevar, 1
Он же по тестам получился самый быстрый.
Еще один способ заключается в том, чтобы запросить по определенному полю, например id, указав точное число для него.
SELECT * FROM `table` WHERE id >= (SELECT FLOOR( MAX( id ) * RAND( ) ) FROM `proxy` ) ORDER BY id LIMIT 1
Все варианты расписаны тут.
Единственное, что не устроило во втором варианте, это два запроса к базе.
Подстановка ссылок в текст в процентном соотношении.
Накидал вот простенькую функцию, которая запихивает в текст ссылки. Т.е. берется текстовый файл и туда пихаются ссылочки с плотностью, например, 7%. Функция простенькая, писал себе под один проект. Наверно, весь функционал редбаттона по отдельности скоро напишу, надо свой дорген замутить.
Переменные вызова:
$text, сам текст в который пихаются ссылки. string
$prc, int, процент плотности ссылок.
$links, array, массив со ссылками вида http://site.ru
$nobr, bool, 1 или 0. Если, например, текста 500кб а ссылок 3, указывает, обрубать ли текст после последней ссылки(1) или оставить все 500кб с 3 ссылками.
Листинг:
function AddLinksToText($text, $prc, $links, $nobr){ $pos = 0; $string = ""; $totalLinks = count($links); $Words = explode(" ", $text); $totalWords = count($Words); $needText = $totalLinks * $prc; if($totalWords < $needText){ $prc = floor($totalWords / $totalLinks); //calculate recommended percentage if haven't enough text echo @date("r")." not enough text, decrease density to ".$prc."%\r\n"; $needText = $totalLinks * $prc; } else { echo @date("r")." working with text, density is ".$prc."%\r\n"; } foreach($links as $num=>$lnk){ $pos += $prc; $Words[$pos] = "<a href=\"".$lnk."\">".$Words[$pos]."</a>"; } if(!isset($nobr)){ $tmp = array_slice($Words, 0, $needText + 3); } else { $tmp = $Words; } //return string foreach($tmp as $somevar){ $string .= $somevar." "; } return $string; }
Заливка файлов на радикал PHP
Если нет желания забивать сервер картинками, то данный скриптец поможет. Он грузит картинку с веба (урл) на радикал, возвращает адрес картинки на радикале.
$postdata = "upload=yes&F=&URLF=".$imagelink."&O=yes&M=640&JQ=85&J=yes&IM=7&VM=180&R=0&VE=yes&V=Увеличить&X=&FS="; $page = FetchUrl("http://www.radikal.ru/action.aspx", $postdata, NULL, NULL, NULL); preg_match("!id=\"input_link_1\" value=\"(.*?)\"!si", $page, $imageUrl); $imageUrl = $imageUrl[1];
FetchUrl моя универсальная функция для курла, я ее под все подряд юзаю, поэтому там много левого кода. При желании можно поудалять половину.
function FetchUrl($url, $postvars, $timeout, $ref, $blank){ sleep($timeout); echo @date("r")." fetching $url\r\n"; $ch = curl_init(); if(isset($postvars)){ echo @date("r")." $postvars\r\n"; curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postvars); } // curl_setopt($ch, CURLOPT_PROXY, $proxy); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); // curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_TIMEOUT,15); curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); curl_setopt($ch, CURLOPT_COOKIEJAR, "c1.txt"); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; U; Linux x86_64; ru; rv:1.9.1.6) Gecko/20091201 SUSE/3.5.6-1.1.1 Firefox/3.5.6 FirePHP/0.3"); curl_setopt($ch, CURLOPT_COOKIEFILE, "c1.txt"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_URL, trim($url)); curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE); curl_setopt($ch, CURLOPT_REFERER, $ref); $result = curl_exec($ch); if($blank == "1"){ $result = preg_replace("/\n/", "", $result); $result = preg_replace("/\r/", "", $result); } curl_close($ch); return $result; }
Многопоточность в php
Оффициальной нет, сразу скажу. Есть только многочисленные костылики. Примеры, в основном, будут полезны в сео софте.
Встала вобщем задача передо мной — накатать многопоточный нескажу что, причем не просто многопоточный, а чтобы еще и потоками можно было управлять, как в том же делфи. То есть, чтобы можно было поток остановить, запустить, запауазить, возобновить и потоки еще должны оповещать о своем состоянии, мол в данный момент выполняю то-то. Read On…