Roadsend php compiler и Roadsend php IDE (бесплатная последняя версия 2.9.0-beta)

Наконец я нашел откомпилированную версию сабжа, и теперь ее можно скачать бесплатно, без СМС и вирусов отсюда. IDE, тащемта, дерьмо, но это можно простить, ибо писалось все это дело в 2008 году, но до сей поры ничего лучшего никто не написал.
Не буду подробно рассказывать, чего мне это стоило, но было нагажено одному болгарскому файл-хостингу и инсталлятор пришлось избавлять от вирей, распространяющих рекламу и майнящих криптовалюту.
Избавили и выкладываем в нормальный открытый доступ. Кто умеет в торренты, помогите и выложите на Рутрекер и TPB, оно маленькое 20 мегабайт всего. Но очень полезное.

Итак: Roadsend PHP Studio (IDE) + Roadsend PHP Compiler
Компилятор PHP для Windows.
Умеет компилировать PHP в EXE в нескольких режимах:
— Console application — на выходе получается стандартное консольное приложение для Win32
— Desktop GUI Application — десктопное оконное приложение, для того, чтоб его собрать нужны еще библиотеки и инструментарий PHP-GTK, в комплекте нет
— Compiled Web Application (FastCGI) — скомпилированное Web-приложение, в экзешник встраивается FastCGI.
— Standalone Web Application (MicroServer) — почти тоже самое, но в экзешник встраивается Web-сервер от Roadsend.
-Library — компилирует полноценный DLL из PHP-кода, который можно встроить в свое приложение, хоть на C#, хоть на C++, хоть на небе, хоть на Аллахе.
Компилировать может в двух режимах — dynamic и static, В статическом режиме в экзешник внедряются DLL от Sheme на котором написан сам компилятор, и их не надо таскать за собой, в динамическом режиме — будет надо, но в статическом вырастает размер готового экзешника, примерно на мегабайт.

Проблемы:
— В Windows 7 не работает штатный лаунчер для IDE (сам компилятор работает).

Пришлось вспомнить молодость и расчехлить OllyDebug, вытащить из лаунчера команду, которой он запускает основной файл IDE. По итогу вышел вот такой небольшой батник, который заменяет оригинальный лаунчер:

@echo off

set ROADSEND_ROOT=#put you Roadsend root directory here, e.g. C:\roadsend#
set SH=\bin\sh.exe
set IDE=\pcc\bin\loon.exe

if not exist %ROADSEND_ROOT%%SH% goto NOSH
if not exist %ROADSEND_ROOT%%IDE% goto NOIDE

echo Files OK.
echo Launch Roadsend IDE...
%ROADSEND_ROOT%%SH% --login -c "cd /pcc/bin && start loon"


:NOSH
	echo File %ROADSEND_ROOT%%SH% not found
	exit /b 1

:NOIDE
	echo File %ROADSEND_ROOT%%IDE% not found
	exit /b 1

куда вместо #put you Roadsend root directory here, e.g. C:\roadsend# надо вставить директорию, куда установлена IDE с компилятором.

Впрочем, Леша, заглаживая вчерашний демарш, написал свой лаунчер с азартными играми и продажными женщинами на C# и даже с инсталлятором.

Подробнее про Roadsend PHP Compiler и Roadsend PHP Studio можно прочесть в статье на Хабре

Скачать бесплатно, без СМС и вирусов

Оригинальный инсталлятор Roadsend PHP Studio (IDE + компилятор)

Лаунчер для Windows 7 (C#) с Mega.nz
Лаунчер для Windows 7 (C#) с GitHub

Лаунчер для Windows 7 (BAT/CMD) с Mega.nz
Лаунчер для Windows 7 (BAT/CMD) с GitHub

Прочие ссылки

Статья о Roadsend PHP Compiler на Хабр Копия
Исходники лаунчера
BAT/CMD лаунчер на PasteBin

Определение IP и местоположения посетителя сайта 7.

Консольный вариант скрипта.

Т.е. это уже не совсем «определение местоположения посетителя сайта», это просто интерфейс к базе данных Sypex Geo, который можно использовать в консольных приложениях на PHP.

Что переделано:
Переделан изначальный скрипт, для работы под консоль, или, если хотите, а качестве stand-alone скрипта. Для консольного приложения очень важно вернуть код завершения, чтобы далее его могло обработать либо следующая программа в командном файле (BAT/CMD), либо вызвавшая скрипт, как внешний процесс, программа.

Таким же образом был немного подправлен SxGeo.php, распространяемый разработчиками Cypex Geo.

Исправления таковы:

— Везде, где скрипт завершает работу, была добавлена выдача кода завершения
— Таким же образом подправлен класс SxGeo, поставляемый разработчиками Cypex Geo.

Краткая справка скрипта:

Вызов скрипта:
consxgeo.php <ip-address> <database-path> [FIELD_NAME]
consxgeo.php --spec
consxgeo.php --help

--help - Помощь
--spec - Список зарезервированных диапазонов IP-адресов
<ip-address> - Адрес IPv4 (например, 8.8.8.8)
<database-path> - Путь к файлу SxGeoCity.dat
[FIELD_NAME] - Для включения в вывод результата работы скрипта источника IP-адреса. По умолчанию, это значение = MANUAL

Коды завершения:
0 - OK
1 - Предупреждение
3 - Вывод информационных сообщений
4 - Ошибка или неправильные параметры скрипта

Структура ответа:
IP|ISO_CODE|COUNTRY_NAME|CTNR_LAT|CTNR_LON|
REGION_ISO|REGION_NAME|CITY_NAME|CTY_LAT|CTY_LON
|FIELD|MESSAGE|

Пример вывода

Частный IP:


Просто адрес IP:

Сокращенный IP-адрес:

Скрипт на GitHub

Предыдущая часть Копия

PHP. Проверка корректности IP-адреса

Преамбула

[info]ketmar@ljr справедливо заметил, что наши скрипты принимают только IP-адреса в формате xxx.xxx.xxx.xxx, где xxx — десятеричное число от 0 до 255, а IP может быть записан и в виде шестнадцатеричных, и в виде восьмеричных чисел, и даже смешано. Также IP-адрес может быть неполным. Например, адрес 4.0.0.1 можно записать как 4.1
В наших скриптах корректность IP проверялась регулярным выражением, т.к. все равно им же производился поиск IP в полях HTTP_*, в которых IP может передаваться прокси-серверами.
Но валидацию IP можно провести и без использования регулярных выражений. Другое дело, поиск без него уже не произведешь, и это может создать определенные проблемы, если прокси-сервер, например, будет передавать IP в виде шестнадцатеричных чисел или преобразовывать, где возможно, полные адреса в неполные.

Не очень хороший способ валидации IP функцией filter_var()

В PHP 5.2.0 появилась функция filter_var(), которая позволяет проверять строки на соответствие разным форматам, не только IP, но и, например URL или e-mail.
Для проверки IP она вызывается так:

filter_var($ip,FILTER_VALIDATE_IP);
где:
$ip — строка, содержащая IP-адрес
FILTER_VALIDATE_IP — встроенный фильтр для IP-адреса
Функция возвращает TRUE, если строка прошла проверку, и FALSE если нет.

А не очень хорош способ тем, что валидацию проходят только IP, соответствующие формату «четыре десятеричных числа от 0 до 255, разделенных точкой», т.е. работает точно также, как и наша старая функция
Такое ощущение, что разработчики PHP пытаются избавить мир от зоопарка способов записи IP-адреса, и привести все, наконец, к единому знаменателю 🙂

Пример с использованием функции filter_var

Проверка корректности IP-адреса функцией ip2long()

[info]ketmar@ljr предлагал использовать сишную функцию inet_addr(), но где ж я ее возьму-то в PHP, подумал я, и зря подумал. 🙂 Функция ip2long($ip), которая использовалась для проверки попадания IP-адреса в определенный диапазон Копия ее аналог. Если переменная $ip содержит корректный IP-адрес, то функция вернет целое число, если в IP-адресе ошибка, то функция вернет FALSE или -1.

Примечание: Функция ip2long() возвратит FALSE для IP 255.255.255.255 в PHP 5 <= 5.0.2 и -1 в PHP 5 <=5.2.4 на 64-битных системах. Это было исправлено в PHP 5.2.5, теперь возвращается 4294967295. В 32-битных системах будет возвращено -1 из-за целочисленного переполнения.

Так что проверку на корректность IP можно делать в функции-обертке, добавив код-заглушку для IP 255.255.255.255:

function IsIP($ip)
{
	//преобразуем в нижний регистр, на случай шестнадцатиричных чисел
	$ip=strtoupper($ip);
	//ip2long в некоторых версиях php 
	//некорректно реагирует на адрес 255.255.255.255
	//делаем небольшую заглушку
	if ($ip == '255.255.255.255'||$ip == '0xff.0xff.0xff.0xff'||
	   $ip == '0377.0377.0377.0377')
	   {
		   return true;
	   }
	
	$tolong=ip2long($ip);
	
	if ($tolong == -1||$tolong===FALSE) return FALSE;
	else return TRUE;	
}

Преобразование неполных и прочих «необычных» IP-адресов в привычный вид.

В PHP есть функция long2ip(), которая делает обратное преобразование, т.е. преобразует целое число в IP-адрес в привычном виде. Если их совместить, то можно преобразовывать неполные адреса в полные:

function fulladdr($ip)
{
	//преобразует неполные адреса в полные
	//для информации
	$tolong=ip2long($ip);
	return long2ip ($tolong);
}


Пример работы скрипта:
isip.php?ip=4.1

Скрипт на GitHub

Внезапное дополнение

Внедрил последний метод в рабочие скрипты, залил на сервер, и оказалось, что метод не работает. Ну не то, чтобы не совсем не работает, а работает точно так же, как старая функция с регулярным выражением, т.е. возвращает TRUE только если IP-адрес записан в виде четырех десятеричных чисел от 0 до 255, разделенных точкой. Неполные адреса, или адреса в других системах счисления IP-адресами не считаются. Функция ip2long() возвращает FALSE, если ей скормить такой адрес. Уж не знаю, и сходу не нагуглил, отчего такая оказия, то ли такое поведение зависит от настроек PHP, то ли от сервера. На локальном сервере работало, а на том, который в интернете — перестало. Можно сказать, зря делал, но зато сделал валидацию IP без регулярного выражения.

Источники

1. ip2long
2. Ещё раз о filter_var

Определение IP и местоположения посетителя сайта 6.

Нифига не окончание, а второй сезон.

Пока исключительно небольшие исправления.

— Добавили зарезервированные диапазоны IPv4 адресов и соответствующую проверку Копия в скрипты для машинной обработки данных и в красивый скрипт с оформлением, таким образом немножко усовершенствовали скрипт из предыдущей серии.

— Сделали тестовый скрипт, который IP сам ничего не детектит, а просто обращается к SxGeo. Он все равно еще понадобится.

Использование:
onlysxgeo.php?ip=ip-address
Например:
onlysxgeo.php?ip=8.8.8.8
Или:
onlysxgeo.php?ip=ip-address&f=FIELD_NAME
для включения имя поля в ответ скрипта, по умолчанию имя поля MANUAL
Или
onlysxgeo.php?specdiap
Для вывода списка зарезервированных диапазонов адресов IPv4

— По многочисленным просьбам зрителей сделали самый простой скрипт, который просто выводит все IP из заголовков HTTP_* (например HTTP_VIA и/или HTTP_X_FORWARDED_FOR) и REMOTE_ADDR и источник адреса (имя поля HTTP_* или REMOTE_ADDR).

— Завели отдельный репозиторий на GitHub, куда выложили код из всех предыдущих и новых серий

Репозиторий

Запуск php-скрипта в консоли.

Ворчальная преамбула

Дальше будет банальщина, наверняка всем известная, но все же, вдруг кто не знает, да и себе от склероза.

Есть у меня маленький, но очень полезный горшочек скрипт, за которым надо постоянно ходить на сервер, а тут оказалось, что он понадобился на машине, где никаких интернетов нет, а данные, которые нужно обработать — есть. Я сначала решил сделать из него экзешник, но потом оставил эту затею, ибо с компиляторами PHP под Виндовоз неожиданно образовался какой-то жуткий геморрой. HipHop от Facebook напрочь отказался собираться, сайт Roadsend PHP Compiler сдох, а опять собирать с исходников GitHub стало после шаманства с HipHop откровенно влом, ну плюс MinGW особым удобством не отличается.

Заметил, кстати, удивительную странность — на машине с 12 Гб оперативной памяти и четвероядерным процессором, но под MinGW и, соответственно, Виндой, сборка происходит медленнее, чем на компьютере с Linux, скромным двухведерным процессором и двумя же Гб ОП.

Впрочем, все эти танцы с бубном были совершенно лишними.

Запуск скрипта в консоли

Все оказалось банально и элементарно, php прекрасно работает из консоли. Формат команды:

php.exe [параметры] <скрипт> [параметры_скрипта]

Параметры скрипта

Скрипт может «найти» свои параметры в элементах глобального массива $_SERVER:
$_SERVER['argc'] хранит количество параметров
$_SERVER['argv'] их значения. $_SERVER['argv'] сам является индексированным массивом. В элементе 0 содержится имя файла скрипта.

Примечание:
Начиная с PHP 4.3.0, при использовании CLI SAPI переменные $argc и and $argv зарегистрированы и заполнены соответствующими значениями. В более ранних версиях создание этих переменных, так же, как и для CGI или модуля веб-сервера, требует значение on директивы register_globals. Независимо от версии PHP или статуса опции register_global они всегда доступны как элементы массива $_SERVER или $HTTP_SERVER_VARS. Например: $_SERVER[‘argv’]

Пример

Скрипт, выводящий в консоль свои параметры:

<?php	
	echo "Console test \n\n";
	
	echo "Arguments count: ".$_SERVER['argc']."\n";
	echo "Arguments values:\n";
	
	$i=0;
	
	foreach ($_SERVER['argv'] as $arg)
	{
		echo $i.": ".$arg."\n";
		$i++;
	}	
?>

Результат работы

Если запустить скрипт, например так:

php.exe con-test.php param1 param2 param3 tramparamparamparam

Портабельный скрипт

Все это не имело бы большого смысла, если бы для запуска скрипта пришлось бы тащить с собой Web-сервер или весь дистрибьютив PHP, со всеми модулями и прочим. Для минимального запуска PHP под Windows нужно всего 2 файла: php.exe и php*ts.dll, где * — версия PHP. Например, для использованного мной PHP5, это php5ts.dll

Разные мелочи

— Инклюды. Если скрипт подразумевает использование инклюдов, то их лучше держать либо в директории с главным скриптом, либо в поддиректориях, и прописывать в основном скрипте относительные пути. Т.е. так, как это обычно делается на сервере. Иначе PHP будет искать их либо в include_path, который прописан в php.ini, либо вообще неведомо где, точнее ведомо — это указывается как параметр при сборке самого PHP, если мне не изменяет склероз.

php.ini Вообще, для запуска PHP он не нужен, но тут может вкрасться чущественная гадость. Если на машине уже установлен PHP, или php.ini подложен каким-то злоумышленником в каталог по умолчанию, для многих сборок под Windows это %WINDIR%, то может случиться неприятность.
Сам PHP ищет свой php.ini сначала в каталоге с самим собой, так что можно туда его подложить.

— Расширения PHP. Можно подложить нужные DLL расширений в подкаталог в каталоге с php.exe и прописать в extension_dir в php.ini относительный путь к каналогу, а в соответствующих параметрах extension — имена DLL

— PHP я цельностянул из Denwer 🙂

Архив с примером и «портабельным» PHP

Источники

1. Создание EXE приложений на PHP Копия
2. Оффлайновые лекционные тетради в клеточку.

Зарезервированные диапазоны IP-адресов и проверка попадания в них адреса.

Преамбула

В IPv4 имеются зарезервированные диапазоны адресов, в некоторых случаях надо проверить, не попал ли адрес в один из них

Таблица зарезервированных адресов


См. в PDF
Или на PasteBin

Надеюсь, ничего не забыл. Таблица нагло выдрана из лекции, но я сверялся с Википедией и другими интернетами.

Вспомогательные функции для проверки

Для порядку заведем регулярное выражение для проверки IP
$ip_pattern="#(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)#";

И функцию, которая проверяет, а IP ли вообще у нас на входе:

function isip($ip_str) //соответствие данных формату IP
{	
	global $ip_pattern;
	$ret=FALSE;
	if (preg_match($ip_pattern,$ip_str)) 
	{
		$ret=TRUE;
	}
	return $ret;
}

Теперь функцию, которая будет проверять, попал ли IP в нужный диапазон:

function chkdiapip ($user_ip, $ip_from, $ip_to) //попадает ли ip в нужный диапазон
{
	return ( ip2long($user_ip)>=ip2long($ip_from) &&
 ip2long($user_ip)<=ip2long($ip_to) );
}

Проверка

Создадим двумерный массив со списком диапазонов:

$spec_list = array(										
	array ("0.0.0.0","0.255.255.255", "Current network"),
	array ("255.255.255.255","255.255.255.255", "Broadcast"),
	array ("255.0.0.0","255.255.255.255", "Reserved by the IETF, broadcast"),
	array ("10.0.0.0","10.255.255.255", "Private network"),
	array ("100.64.0.0","100.127.255.255", "Shared Address Space"),
	array ("127.0.0.0","127.255.255.255", "Loopback"),
	array ("169.254.0.0","169.254.255.255", "Link-local"),
	array ("172.16.0.0","172.31.255.255", "Private network"),
	array ("192.0.0.0","192.0.0.7", "DS-Lite"),
	array ("192.0.0.170","192.0.0.170", "NAT64"),
	array ("192.0.0.171","192.0.0.171", "DNS64"),
	array ("192.0.2.0","192.0.2.255", "Documentation example"),
	array ("192.0.0.0","192.0.0.255", "Reserved by the IETF"),				
	array ("192.88.99.0","192.88.99.255", "Anycast"),
	array ("192.88.99.1","192.88.99.1", "IPv6 to IPv4 Incapsulation"),
	array ("192.168.0.0","192.168.255.255", "Private network"),
	array ("198.51.100.0","198.51.100.255", "Documentation example"),
	array ("198.18.0.0","198.19.255.255", "Test IP"),
	array ("203.0.113.0","203.0.113.255", "Documentation example"),
	array ("224.0.0.0","224.255.255.255", "Multicast"),
	array ("240.0.0.0","240.255.255.255", "Future reserved")					
	);

И функцию, которая будет все это безобразие в цикле перебирать, и если IP попадет в какой-то из диапазонов - выдаст диапазон и описание. Если не попадет - вернет -1.

function get_spec_diap ($user_ip, $listspec)
{
	for ($i=0;$i<sizeof($listspec);$i++)
	{
		$item = $listspec[$i];
		if (chkdiapip($user_ip, $item[0], $item[1]))
		{
			return $item[0]."\t".$item[1]."\t".$item[2]."\t\n";
		}
	}
	
	return -1;
}

Ну шоб два раза не вставать, сделаем еще и функцию, оглашающую весь список:

function printspecdiap ($listspec)
{
	for ($i=0;$i<sizeof($listspec);$i++)
	{
		$item = $listspec[$i];
		echo $item[0]."\t\t".$item[1]."\t\t\t".$item[2], "\t\t\t\n";
	}
}

Скрипт полностью на PasteBin
На GitHub

Темы

Еще одна заметка от склероза:
Вот ссылка на архив с темами
В архиве и мобильная, и модифицированная основная, со всеми свистелками и перделками.

Кому для чего вдруг надо, просите ключик в комментах на LJR (ну я там чаще бываю, не забудьте регнуться — анонам почта не приходит)

Новости времен апокалипсиса… На своем сайте.

Когда-то, впрочем, не так давно, [info]r_l@ljr сделал офигенный проект — новостные постапокалиптчиеские заголовки. В виде простого скрипта PHP.

Идея крутая, и мне показалось, что неплохо бы ее использовать в дизайне своего сайта. В результате я пошел и спросил у [info]r_l@ljr исходники, а дизайнеры внедрили этот прикол в тему оформления.

Заметка, скорее от склероза, и чтоб не пролюбить… Но мало ли кому понадобится.

При заходе на любую страницу сайта http://tolik-punkoff.com, в его шапке вы можете увидеть сгенерированный «заголовок новости»:


см. ссылку.
см. ссылку

Как эта штука сделана в моей теме и версии WordPress:

Понадобится оригинальный архив (ссылка в конце заметки)

В нем 3 файла:
news_data — файл с массивами фраз для генерации заголовка
global.php — файл скрипта, отображающего заголовок. Новый заголовок генерируется автоматически, через заданное время.
globalf5.php — заголовок генерируется один раз, надо нажать F5, т.е. обновить страницу, чтобы получить новый.

Внимание: в файле news_data пропущена запятая, даже в нескольких местах, так что если сами будете делать, поправьте. На локальном web-сервере, должно быть видно где.

Внедряем скрипт в тему WordPress

1. Закачиваем в директорию темы, например, your-site.org/wp-content/themes/beach/, конкретика зависит от вашего хостера, исправленный файл news_data.
2. Создаем скрипт news.php следующего содержания:

<?php
	$where=array();
	$subject=array();
	$action=array();
	$object=array();
	$parts=array();

	include(__DIR__.'/news_data');

	foreach ($parts as $part) 
	{ 
		$news[$part]=${$part}[mt_rand(0, count(${$part})-1)]; 
	}
	$obs=implode(' ', $news)."&nbsp;";
?>

В конце заметки ссылка на PasteBin

3. Далее находим файл заголовка темы (в редакторе темы WordPress), скорее всего это будет header.php:

В самом начале подключаем скрипт news.php:

<?php
/**
* @package Beach
*/
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
include(__DIR__.'/news.php');

...

Команды ini_set используются для отладки, если что-то пошло не так, скорее всего, вам вывалится сообщение об ошибке. Не буду на этом останавливаться, т.к. подробное описание есть в любом учебнике по PHP, выкиньте эти команды, когда все заработает. include(__DIR__.'/news.php'); подключает ранее созданный скрипт.

4.Внедряем скрипт в header.php, в «шапку» страницы:

...

<h2 id="site-description"><?php bloginfo( 'description' ); ?></h2>
<h3 id="apoknews"><?php echo $obs; ?></h3>
</hgroup>

...

В зависимости от используемой темы, вы сами должны найти место, куда внедрять данный код (выделенный жирным).

5. Подправляем CSS. Файл: style.css

В начале файла дописываем:

#apoknews {
	color: RGB(255, 215, 0);
	background-color: RGB(0, 0, 0);
	text-align:left;
	border: 3px solid #ffd700;
	padding-left: 7px;
}

Ссылки

Код скрипта данных
Код скрипта отображения (news.php)
Фрагмент кода скрипта формирования заголовка header.php.
CSS

Скачать

1. Оригинальный архив
2. Готовый архив.

Форма обратной связи для WordPress, без плагина. Защита от спама и полевые испытания ASCII-каптчи

Или еще раз возвращаясь к напечатанному. Сегодня поговорим о защите от спама.
В первоначально описанном способе копия был баг (промотайте в конец), из-за которого можно было легко и непринужденно загадить ящик получателя спамом, да еще и в автоматическом режиме. Отправить картинки, вирусы, или загадить чужой ящик не получится, но вот закидать «Войной и миром» ящик владельца сайта вполне таки да.
Чтобы уменьшить такую вероятность, добавим в скрипт отправки почты каптчу. Поскольку скрипт, отправляющий почту (mail.php) к компонентам WordPress не относится, то каптчу придется изобретать свою. Лично мне это оказалось даже хорошо, т.к. совсем недавно я писал о создании ASCII-каптчи, копия, и мне прямо-таки жгло показать ее работу в реальном проекте, а не только в учебных примерах. Посему ее и используем для защиты от спама.

Постановка задачи

Переписать скрипт mail.php так, чтобы он смог использовать ASCII-каптчу.

Краткое описание процесса

1. Пользователь в форме обратной связи, вводит сообщение.

2. По нажатию кнопки «Отправить» сообщение передается скрипту mail.php
3. Если сообщение было отправлено из формы, то скрипт генерирует каптчу, HTML-страницу, содержащую параметры сообщения (имя, текст, электронный адрес пользователя), ASCII-изображение каптчи, поле для ввода кода, элементы управления (кнопки) с помощью которых пользователь может ввести код, обновить код подтверждения, отправить код и сообщение.
4. Скрипт также должен обработать возможные ошибки. Если они есть, пользователю выводится соответствующее сообщение и страница с формой ввода сообщения открывается вновь.
5. Если каптча введена неверно, пользователю демонстрируется сообщение об ошибке ввода каптчи, и дается возможность повторить ввод каптчи. Информация в сообщении сохраняется.
6. Если код введен верно и другие ошибки отсутствуют, сообщение передается на заранее указанный в скрипте e-mail.
Далее подробное описание скрипта

А ТЕПЕРЬ, ВНИМАНИЕ, ВОПРОС
Обход этой каптчи:

Реализация не совсем промышленная. Мне хочется, чтобы вы подумали, над тем, как данный способ защиты обойти. Можете воспользоваться своим методом и попытаться заспамить мне почтовый ящик. Кто заспамит — получит минус два вопроса на зачете.
Можно спамить просто так, но желательно, с описанием способа. Я знаю 5.

Комментарии на lj.rossia.org будут открыты для всех, можно анонимно предлагать, как способы обхода, так и способы защиты. Стирать не буду ничего, кроме флуда, спама и личных оскорблений.

Для самых ленивых, кто не удосужился все прочесть. Инструкция по установке.

Форма обратной связи для WordPress, без плагина здесь или здесь

Все делается так же, с той лишь разницей, что обновленный архив скачиваете по ссылке ниже, и не забываете закачать captcha.php в директорию темы, вместе с mail.php.

Ссылки

Смотреть код скрипта на PasteBin
Скачать все одним архивом
Тесты и куски кода

Заметка в PDF

Маленькая заметка о редиректе средствами PHP.

Редтрект в PHP осуществляется с помощью функции header(), и в ее использовании есть небольшая проблема. Она должна быть вызвана ДО любого вывода текста, т.е. до вывода любых тегов, текста, и т.д.
Можно не бояться за то, что текст, выведенный после функции header() пользователь вообще не увидит. Увидит, если установить нужный параметр — время до редиректа, например, так вот:

header( 'Refresh: 5; url=http://natribu.org' );

Цифра 5 указывает на время в секундах, которое пройдет перед тем, как пользователь будет перенаправлен на далее указанный адрес (в данном случае http://natribu.org, хехе).

Следующий код вызовет ошибку:

<?php
	echo "Вы будете посланы нахуй через 5 секунд";
	header( 'Refresh: 5; url=http://natribu.org' );
?>

Warning: Cannot modify header information — headers already sent by […]

Смотреть скриншот

А следующий код сработает правильно:

<?php
	header( 'Refresh: 5; url=http://natribu.org' );
	echo "Вы будете посланы нахуй через 5 секунд";	
?>

Через 5 секунд:

Две и более кнопки submit в форме HTML. Обработка на PHP.

Случилась тут небольшая задачка, как обработать две и более кнопок submit в HTML-форме, причем желательно без помощи JS и иных ухищрений, т.е. есть, например, такая форма:

Надо выяснить (на сервере), какую кнопку нажал пользователь.

На самом деле (ну если никто не поизвращался над браузером, т.е. клиентом) в отправленном серверу запросе POST будут только параметры нажатой кнопки. Если задать каждой кнопке уникальное имя, то можно будет отследить, какая кнопка была нажата, и, соответственно, обработать это.

Создадим тестовую форму multibutton.html:

<html>
	<head>
		<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
		<title>Multibutton 'Send' Test</title>
	</head>
	<body>
		<center>
			<form action='multibutton.go.php' method='POST'>
				<b>Press a button</b></br>
				<input type='text' name='testtext' value='Test Text'></br>
				<input type='submit' name='button1' value='Button #1'>
				<input type='submit' name='button2' value='Button #2'>
				<input type='submit' name='button3' value='Button #3'>
			</form>
		</center>
	</body>
</html>

На PasteBin

И напишем скрипт-обработчик multibutton.go.php:

<?php
$buttonmessage="<center><b>Perssed button:</br>#";
				
		//Проверка кнопок
		if (isset($_POST['button1']))
		{
			$buttonmessage.="1";
		}
		
		if (isset($_POST['button2']))
		{
			$buttonmessage.="2";
		}
		
		if (isset($_POST['button3']))
		{
			$buttonmessage.="3";
		}
				
		echo $buttonmessage."</br>";
		echo "Test text value: '".$_POST['testtext']."'</b></br></br>";
		echo "<b>----- Output $_POST array: ----</b></br><code><pre>";
		print_r ($_POST); echo "</br></pre></code>";
		echo "<b>-------------------------------</b></center>";
?>

Если в массиве $_POST будет найден элемент button1 — обрабатываем нажатие кнопки #1 (if (isset($_POST['button1']))), аналогично поступаем с другими кнопками. Текстовое поле — исключительно для теста, можно вписывать любое значение, оно будет показано пользователю.
Для наглядности выводится содержимое массива $_POST:

print_r ($_POST);

Код на PasteBin

Получим следующее:
Нажата кнопка #1:


Нажата кнопка #2:

Нажата кнопка #3:

Можно объединить создание формы и вывод результата в единый скрипт: см. код на PasteBin

Источник

Две и более submit кнопки в форме

Скачать пример

ASCII-каптча, каптча псевдографикой. Часть III. Примеры использования.

Сразу оговорюсь, это учебные примеры. В ближайшее время я вернусь к теме и покажу, как использовать каптчу «на местности», т.е. встроить ее в работающий движок сайта или его часть. А тут пока примеры относительно скорее умозрительные, что называется, из учебника.

Каптча и механизм сессий.

Если кто-то вдруг совсем не знает, что это такое, то в конце заметки есть ссылка на источник, ну или можно в поисковик сходить.

Код тестового скрипта вполне неплохо обкомментирован, поэтому особых пояснений не требует. Если уж возникнут вопросы — задавайте, постараюсь ответить.

Код на PasteBin

Использование cookie для проверки каптчи

Механизм сессий на самом деле не всегда удобно использовать, например, если не хочется возиться с уже продуманными умными людьми сессиями готового сайтового движка, а свою каптчу встроить хочется. В таком случае просто перекладываем всю работу на cookie, создаваемые и удаляемые по нашему хотению:

Код на PasteBin

Тут поясню лишь один момент, установку самих cookie. Делается это встроенной функцией PHP setcookie, полное описание которой вы можете найти в разделе источников в конце заметки.
Мне же понадобились только три параметра:
setcookie($name,$value,$expiredtime);
где:
$name — имя cookie
$value — передаваемое в cookie значение, сохраняемое на компьютере пользователя
$expiredtime — срок действия cookie, после его окончания cookie не будет обрабатываться сервером. Таким образом устанавливается максимальное время, данное пользователю на ввод кода каптчи.

В данном случае:

setcookie('mycaptchamd5',md5($captchacode),time()+300);

т.е. имя cookie 'mycaptchamd5', в качестве значения передается md5-хэш кода каптчи, а время действия устанавливается в 300 секунд (т.е. 5 минут).

Смотреть код или скачать готовый вариант

Код модуля ASCII каптчи на PasteBin
Пример с сессией
Пример с cookie
Цифры псевдографикой. Вариант 1
Цифры псевдографикой. Вариант 2

Скачать все с Mega.nz в одном архиве

Источники

Функция setcookie()
Разработка CAPTCHA своими руками
Копии

Предыдущие части

Часть I
Часть II

ASCII-каптча, каптча псевдографикой. Часть II. В которой генерируется каптча.

Итак, закончили мы на том, что нарисовали все цифры, создали массивы php с псевдографическими изображениями цифр и написали отладочную функцию, которая выводит конкретную цифру. Продолжаем!

Для начала условимся, то нашему злодею-хацкеру, распознающему каптчу, мы, хоть и ненамного, но усложним задачу: «пробельные» («пустые») символы в изображении каждой цифры, а также сами символы, изображающие цифру, будут выбраны случайно из заранее заданного набора. Зададим набор символов, изображающих цифру, в виде строки:

$pgstring="#$%@!?0"; //символы, из которых будут составлены цифры

Аналогично и для «пустых» символов:

$spstring="- "; //пробельные символы

Тут все зависит от вкуса, цвета и лично ваших глазок. Главное, чтобы в строке с возможными «пустыми» символами и в строке с возможными символами, изображающими цифру, не встретилось одинаковых символов, иначе при определенных условиях, пользователь вполне может получить вот такую вот гадость, вместо каптчи:

###### ###### ###### ###### ###### ###### ######
###### ###### ###### ###### ###### ###### ######
###### ###### ###### ###### ###### ###### ######
###### ###### ###### ###### ###### ###### ######
###### ###### ###### ###### ###### ###### ######

Заведем еще две переменные, которые будут хранить выбранные символы для «пробельных» и символов изображения:

$pgchar="";
$spchar="";

Пока просто оставим их пустыми, потом к ним еще вернемся.

Далее подробное описание скрипта с картинками и видео

Итого

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

Код каптчи

Смотреть на PasteBin

Начало здесь
Продолжение

ASCII-каптча, каптча псевдографикой. Часть I.

Сегодня будем рисовать каптчу. Причем не с помощью стандартных библиотек вывода графики (таких мануалов в сети более чем достаточно), а каптчу, отображаемую пользователю в виде псевдографики, т.е. изображения символов каптчи будут созданы из обычных числовых и буквенных символов. Для упрощения задачи примем следующее:

— В качестве символов, из которых будет создаваться изображение, будем использовать латинские буквы, цифры и знаки препинания. Можно, конечно, и китайскими иероглифами пользоваться, но не факт что пользователь сможет каптчу распознать и она у него не «поплывет».
— Сам код каптчи будет состоять только из цифр (ну вот лень мне было заморачиваться с буквами в ASCII-арт).

Плюсы:
+ Скрипт легко встраивается как медведевский будильник, в разные места в любое место, где нужна каптча.
+ Не требует библиотек обработки изображений, дополнительных ранее нарисованных картинок и т.д., соответственно, будет работать даже на самом плохом хостинге, где библиотек типа ImageMagick может вообще не быть
+ Отображается даже в консольном (текстовом) редакторе типа lynx.
+ Почти не тратит трафик (текст же) и ресурсы сервера.

Минусы:

— Довольно легко ее распарсить автоматически, если не применять всякие дополнительные фишки, типа изменения количества строк и столбцов изображения. Их, к сожалению, в этом мануале не будет, но если кто-нибудь захочет вдруг, то я вернусь к этому вопросу.

В части первой займемся рисованием цифр. Конечно, человеку увлекающемуся ASCII-артом это нафиг не надо, можно сразу пропускать и переходить ко второй части. Кто не знает, что такое ASCII-арт вообще, тот может сходить в Википедию или Гугль, и ознакомиться с темой.

Я сам не великий ASCII-сенсей, так что использовал достаточно стандартную методу:

1. В любом простом текстовом редакторе (Блокноте, Notepad++, mcedit или редакторе FAR-а) нарисуем поле размером в X символов и Y строк каким-либо одним символом, например *, -, # или любым другим. Должно получиться что-то типа этого (я взял поле размером 6 x 5 символов):

------
------
------
------
------

2. Далее, нажимаем клавишу Insert, включаем режим замены и заменяем в этом поле символы - на какие-нибудь другие, так, чтобы получилось изображение определенной цифры, например:

-0000-
00--00
00--00
00--00
-0000-

Если кто-то ленивый, то можно поискать готовые цифры в Гугле, взять несколько черновой вариант здесь, готовый, используемый мною вариант здесь. Или можно вообще в последней части статьи скачать сразу весь архив. XD

Итак, у нас есть готовые изображения цифр, осталось лишь записать их в виде, доступном PHP.

Создаем массивы, содержащие псевдографические изображения цифр. Здесь и далее условимся, что в качестве «пустого» символа я использовал *, а в качестве символа для изображения цифры, знак $.
Код и некоторые пояснения
В следующей части создадим генератор кода каптчи и генератор ее ASCII-изображения.

Форма обратной связи для WordPress, возвращаясь к напечатанному.

Или как я избавился от слишком назойливой опеки антиспама на сервере.

Не так давно поднимал вопрос о форме обратной связи для сайта на WordPress [Копия].

Некий анон хотел меня затроллить, но, как обычно, мало того, что написал полнейшую чепуху, которая не работает, так еще и случайно помог вскрыть баг (хотя, скорее опцию) почтового сервера, которая, правда, лично мне мешала.

Ситуация такая: антиспам финского сервера (вполне оправданно, кстати) отправляет в спам письма с доменов .ru (mail.ru и yandex.ru точно), .kz, .by и некоторых не связанных с ГОРФ, типа .tk

Но, со спамом я неплохо справляюсь самостоятельно, и лишняя опека со стороны умной машины мне не нужна. На случай, мало ли у кого возникает аналогичная проблема, вот рецепт:

Находим в скрипте mail.php строчку:

$mes = "Имя: ".$name."\n\nТема: " .$sub."\n\nСообщение: ".$message."\n\n";

И меняем ее на:

$mes = "Имя: ".$name."\n\nТема: " .$sub."\n\nСообщение: ".$message."\n\n"."E-mail to answer: $email\n\n";

Ниже меняем в строке

$send = mail ($address,$sub,$mes,"Content-type:text/plain; charset = UTF-8\r\nFrom:$email");

$email на $address. Должно получиться:

$send = mail ($address,$sub,$mes,"Content-type:text/plain; charset = UTF-8\r\nFrom:$address");

Что этот код делает. Да все просто. Строка с сообщением ($mes) изменяется так, что адрес, который ввел пользователь в контактной форме, добавляется к тексту сообщения как простой текст. Параметры функции php mail изменяются так, что в заголовок письма вместо адреса пользователя, добавляется наш собственный адрес для приема сообщений из контактной формы. В результате мы получим сообщение, отправленное с нашего же адреса. Примерно как на скриншоте ниже:

Проблема с антиспамом решилась (сервер проверял только заголовки писем, а не указанные в тексте адреса), единственный минус — не ответить по нажатию соответствующей кнопки в почтовой программе, но тут уж, как говорится, шашечки или ехать.

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

Заметка в PDF

Форма обратной связи для WordPress, без плагина.

Пост из серии «кратенькая инструкция от склероза», описываю больше для себя, как форма сделана на моем сайте. Мопед не мой, но найти, откуда взята сия метода, не смог.

0. Создаем новую страницу, озаглавливаем ее согласно случаю, например Обратная связь, устанавливаем простое и понятное название постоянной ссылки, например contact-form, вставляем в редакторе в режиме Текст вот этот вот html-код. Не забудьте заменить beach на название директории с вашей темой. Пока ничего работать не будет, но «болванка» странички с формой обратной связи готова, осталось лишь научить сайт обрабатывать запрос, отправленный из формы.
1. Нам понадобится php-скрипт, отправляющий почту. Создаем файл mail.php, вставляем код, который откроется по ссылке, и копируем файл по FTP в директорию темы (wp-content/themes/ваша-тема).
В исходнике mail.php надо заменить admin-vnc@uaitc.fi на тот e-mail, на который вы хотите получать сообщения, отправленные из этой формы и указать в строке
header( 'Refresh: 3; url=http://tolik-punkoff.com/obratnaya-svyaz/' ); нужный адрес, куда пользователь будет перенаправлен после отправки сообщения. Число (в данном случае 3) — время перед перенаправлением. Фактически время, которое пользователю будет отображаться сообщение об успехе, либо об ошибке при отправке сообщения.
2. Сохраняем два изображения, valid.png:


и invalid.png:

в директорию images темы (wp-content/themes/ваша-тема/images).
3. Добавляем в файл style.css темы вот этот вот код css
4. Осталось проверить, все ли работает и добавить ссылку на страницу в соответствующее меню.

Вот что должно получиться

ФАНФАРЫ!

Все необходимое в одном архиве (на mega.nz)
Нашел оригинальный архив (скачать с mega.nz)

Код, добавляющий тег rel canonical

Чтоб не потерять.
Автора оригинала не ведаю, но помню, что в оригинале был какой-то глюк, исправили. Вроде работает, и даже правильно. 🙂

Вставлять в начало файла functions.php шаблона темы.

На Pastebin
На Mega.nz

HTTP-редирект в WordPress.

Чуть не забыл, ко вчерашнему разговору с товарищем, который про это спрашивал. Ну я тебя, товарищ, немного надул, ибо не погуглил. Не надо никаких костылей с header ('Location: http://natribu.org'), если по каким-то причинам надо делать редирект со страниц WordPress, то есть стандартная функция

wp_redirect( $location, $status );
где:
$location — адрес, куда посылаем.
$status — код HTTP, статус перенаправления.

Подробности, например, тут [Копия]

Вот тестовый шорткод, работает, но где-то реально использовать тупым копипастом не сильно рекомендую, тому ще, во-первых, нет ни единой проверки, во-вторых, если он будет доступен нечестному юзеру, то юзер таким образом может перенаправить хороших пользователей на какую-нибудь бяку, а в-третьих, в мануале написано, что оно из шорткода вроде как работать не должно. Но у меня работает. Так что использовать просто как пример вызова функции wp_redirect и внимательно читать мануал.

Страница со списком тегов (или рубрик) WordPress

Если перейти в блоге WordPress по ссылке на любой тег, то попадем на страничку, содержащую анонсы постов по данному тегу, адрес странички будет примерно такой:

http://tolik-punkoff.com/tag/manuals/

Где manuals — собственно, выбранный тег, а tag — префикс для URL-адреса меток, который можно настроить в консоли WordPress в разделе Настройки — Постоянные ссылки.

Идея такого формата адреса достаточно очевидна, убираешь из строки адреса выбранный тег и попадаешь в список всех тегов, как например это сделано в ЖЖ или LJR

Вообще-то в профессиональной теме WordPress это дело должно бы работать из коробки, потому что вообще-то плохо, если раздел сайта, который логически существовать должен, не существует. И так думаю не я один, а как выяснилось из логов, и роботы. Правда это оказался робот какого-то мелкого поисковика, не Google или Яндекса, но все равно неприятно.
Так вот, если тема не сильно профессиональная, или разработчик забыл о такой мелочи, то посетитель сайта попадет по такой ссылке на страницу 404.

Исправляем досадную неприятность.

Читать далее…

Скачать заметку в формате PDF

Cut в стиле livejournal в блоге WordPress

В WordPress откровенно не хватает ката в стиле ЖЖ, собственно кат-то там есть, но он монументален, как египетская пирамида и неумолим, как топор палача.
Тег <!--more--> можно использовать лишь один раз в посту, и все что после него уходит в подкат.


Кат как в ЖЖ, напротив, может позволить скрыть несколько частей записи (длинные участки кода, крупные картинки) оставив остальное видимыми читателю с основной страницы блога.

Удивительно, что никто эту ситуацию до сей поры не исправил, ни разработчики, ни авторы многочисленных плагинов. Конечно, попадались всякие статьи и исходники на тему «как сделать спойлер», но это были не устраивающие меня решения на javascript или ухищрения с CSS. И одно и другое плохо, во-первых, зависимостью от конкретного браузера, а во-вторых, тем, что зря занимает канал клиента, т.к. крупная картинка под спойлером или куча текста все равно будет загружена в клиентский браузер.

Итак, необходим следующий функционал:
1. Кат в стиле живого журнала, поддерживающий изменение текста ссылки на содержимое под катом, с возможностью использоваться несколько раз в одном посту для скрытия определенных его фрагментов.
2. Сделано это должно быть без javascript и CSS.

Как устроен кат в ЖЖ.

На главной странице блога область текста, находящаяся между тегами <lj-cut> и </lj-cut> заменяется на ссылку вида http://blog.livejournal.com/1234567.html#cutid1 со стандартным текстом Read more… или текстом, заданным пользователем. Где
1234567.html — страница, содержащая полный текст поста
cutid1 — якорь [4], указывающий на начало скрываемого текста на странице поста.
Правда, в такой реализации тоже есть один минус — имена якорей генерируются автоматически, в зависимости от количества участков, скрытых под катом в посту (cutid1, cutid2... cutidN).

Ну ладно, писать, так писать, подумал я и решил добавить возможность задавать осмысленные имена якорей, например, #code, #function, #ioann_grozny_killing_son_2666_x_6666 и т.д.

Как сделать в WordPress кат в стиле Живого Журнала?

Тут на помощь придут шорткоды [1]. Можно написать плагин, реализующий такой функционал и добавляющий шорткод [lj-cut]] [[/lj-cut]

Создаем «болванку» плагина

В директории wp-content создаем поддиректорию lj-cut, а в ней файл lj-cut.php со следующим содержимым:

<?php

/*
Plugin Name: LJ-cut style cut
Description: Add Livejournal-like Cut Shortcode 
*/


function ljcut_shortcode($atts, $content=null)
{			
	
}

add_shortcode ('lj-cut','ljcut_shortcode');

?>


Информация в комментариях после Plugin Name: и Description: будет отображена в админ-панели в разделе плагинов. Plugin Name: и информация далее должна быть указана обязательно.
Функция ljcut_shortcode($atts, $content=null) обрабатывает шорткод, ей передаются движком массив с параметрами $atts и содержимое между открывающим и закрывающим тегом $content
Функция add_shortcode добавляет шорткод с указанным именем (1 параметр) и устанавливает функцию его обрабатывающую (2 параметр).

Описание и алгоритм.

Функция обработки шорткода будет вызвана каждый раз, как будет встречена в посту. Ей будут переданы параметры из массива $atts, указанные в тексте как [shortcodename param1="value1", param2="value2"].

1. Заведем 2 статических переменных:
static $cutid=0; //номер текущего cutid в посту
static $oldplink=''; //предыдущий permalink
Первая будет хранить номер текущего cutid в посту, а вторая сохранять предыдущую постоянную ссылку на пост. Переменные обязательно должны быть объявлены при помощи ключевого слова static, иначе их значения будут сброшены при каждом вызове функции.

2. Вытащим из массива $atts параметры и запишем их в соответствующие переменные. Если параметр не будет определен, то ему будет присвоено значение, указанное в кавычках после =>

extract(shortcode_atts(array(
	      'text' => 'Read more...',
	      'unicancor' => '',
	), $atts));


4. Получим URL поста, откуда была вызвана функция обработки шорткода, используя внутреннюю функцию WordPress get_permalink() [2]:
5. $plink=get_permalink(); //получаем URL текущего поста
6. Получим URL текущей страницы:
$clink=get_bloginfo('url').$_SERVER["REQUEST_URI"]; //URL текущей страницы
Функция get_bloginfo('url') получит адрес блога [3], а в элементе REQUEST_URI массива $_SERVER будет находиться значение вида /blog/post.html если пользователь читает пост на странице поста и значения вида /page/2/ (/author/tolik-punkoff/, /tag/it/), если пост читают с какой-то из страниц сайта. В первом случае необходимо показывать весь текст, во втором — заменять скрытую под катом часть на соответствующую ссылку.
7. Далее необходимо проверить, какой раз функция обработки шорткода ката вызывается из поста. Делается это путем сравнения заранее сохраненной постоянной ссылки на пост и только что полученной.
Если ранее сохраненная ссылка не такая же, как и полученная во время вызова функции, значит, мы начали обрабатывать новый пост. В таком случае отсчет текущих фрагментов, скрытых под катом, необходимо начать заново, а постоянную ссылку на новый пост сохранить в соответствующей переменной. Иначе функция была очередной раз вызвана из текущего поста, соответственно, нужно просто увеличить счетчик фрагментов под катом:

	if ($oldplink!=$plink) //пост новый, надо начать отсчет cutid заново (с 1)
	{
		$cutid=1;
		$oldplink=$plink; //и сохранить текущий 
	}
	else //мы все еще обрабатываем старый пост
	{
		$cutid++; //прибавляем значение cutid
	} 


8. Далее необходимо сравнить постоянную ссылку на пост (premalink) со ссылкой на той странице, на которой находится пользователь и если пользователь на странице поста — установить якорь [4] и вывести контент, скрытый под катом. Если пользователь на одной из страниц блога со списком постов, то выводится ссылка на пост, дополняемая указателем на якорь (http://tolik-punkoff.com/tag/it/post#ancor).
Если имя якоря задано пользователем в соответствующем параметре шорткода, то оно и используется, иначе, якорь принимает вид cutidN, где N — заранее посчитанный в переменной $cutidномер.

if ($plink==$clink)
	{
		//мы в теле поста, cut надо раскрыть и вставить якорь
		if ($unicancor=='') //если якорь не задан, используем cutidn
		{
			$ret='<a name="cutid' . $cutid . '"></a> ' .$content;
		}
		else
		{
			$ret='<a name="' . $unicancor . '"></a> ' .$content;
		}
	}
	else
	{
		//мы на одной из страниц, но не в самом посту
		//надо установить ссылку на пост и на нужный якорь в посту
		if ($unicancor=='') //если якорь не задан, используем cutidn
		{
			$ret='<a class="more-link" ' . 'href="' . $plink . '#cutid' . $cutid .
			 '">' . $text . '</a>';
		}
		else
		{
			$ret='<a class="more-link" ' . 'href="' . $plink . '#' . $unicancor .
			 '">' . $text . '</a>';
		}
	}


Сохраняем сгенерированный HTML-код в переменной $ret
9. Возвращаем сгенерированный код и завершаем функцию обработки шорткода:
return $ret;

Скачать плагин

С Pastebin
С Mega.nz
Страничка плагина на сайте HexProject
Страничка плагина на GitHub
Скачать с tolik-punkoff.com

Используемые источники

1. Шорткоды в WordPress
2. get_permalink()
3. get_bloginfo()
4. Якорь (HTML)