C/C++/PHP5. About Windows services

Предположим, нам необходимо воспользоваться неким скриптом, который должен циклически ожидать каких-либо внешних изменений, реагируя определенным действием в ответ. Вроде бы не сложно. Инициируем сие скрипт в системе посредством автозагрузки. Но как-то это не серьезно.
Другое дело - реализовать скрипт через службы. Далее рассматриваются службы систем win32. Скриптовая часть - php-файл, batch-файл, да что угодно. Попробуем создать службу стандартными средствами самой системы:

sc create tester start= auto binPath= c:\tester\tester.php

В базу служб будет занесена запись о новой службе tester. Попытаемся запустить ее. Ну как? Нас ждет сообщение об ошибке запуска службы. Не смотря на это в "инете" такого рода решения встречаются очень часто. Правда там же предлагают дополнительные шаманства в реестре. Вам это по-душе? 
Если немного порыться в источниках Microsoft, можно узнать, что binPath должен "смотреть" на exe-файл. Немного "покодив" можно создать прототип нашего скрипта. Но после очередного теста стало ясно, что и это не прокатывает. В чем тогда дело? А в том, что служба - непросто исполнимый файл, это нечто большее. Вот пара ссылок на то, чтобы понять суть слова - большее:

Скелет службы (service) на Visual C++
http://dobrunov.ru/2009/08/service-visual-c.html

Beginner's introductory guide to writing, installing, starting, stopping NT services
http://www.codeproject.com/Articles/1697/Beginner-s-introductory-guide-to-writing-installin

Создание своего Windows Service
http://habrahabr.ru/post/71533/

Using Services
http://msdn.microsoft.com/en-us/library/ms686953%28v=vs.85%29 

Таким образом необходимо разработать службу. Но все же как нам не терять связи с нашим изначальным скриптом. Мое решение таково: 1) при создании службы в системе, создаем дополнительную переменную окружения; 2) при запуске службы в данную переменную заносим соответствующее значение и далее запускаем сам скрипт, который циклически просматривает значение переменной окружения; 3) соответственно, остановка службы должна приводить к изменению значения данной переменной, что будет указывать скрипту на необходимость завершения своей работы.
В данном случае переменные окружения могут выступать как посредники между exe-службой и скриптовой частью. Это подобие глобальных переменных в PHP.


C/C++. Quine. Куайны или квайны

Что такое куайн или квайн программирование?
Куайн, квайн (англ. quine) — компьютерная программа (частный случай метапрограммирования), которая выдаёт на выходе точную копию своего исходного текста.
На днях столкнулся с подобной задачей: реализовать на С++ куайн или квайн, но с одним но - вывести текст не на стандартное устройство вывода (например, консоль), а во внешний текстовый файлик (например, output.txt).
Пришлось немного поломать голову. С одной стороны - просто, а с другой начинаешь себя спрашивать - с какого угла подойти? Немного помогла статья с "хабры" - "Как писать квайны":
Введение 
Многие программисты считают написание квайнов (программ, выводящих свой исходный код) непосильной задачей. И действительно — все эти цепные квайны и квайны различного порядка, при взгляде на которые можно потеряться в казалось бы бессмысленном наборе символов…
Однако на самом деле написать квайн на каком-либо языке не так сложно, как кажется. Сейчас я расскажу, как сделать это на различных языках программирования. Более того, мы не будем использовать «хаки» интерпретеруемых языков вроде операции вывода исходного кода и функций типа eval, а также напишем квайны на интерпретируемых и компилируемых языках.
Теория
Попробуем написать квайн. Для этого возьмём инструкцию языка для вывода и передадим ей как параметр код программы. Однако в коде мы снова используем этот же код и так далее — возникает бесконечная рекурсия. Но что можно сделать для того, чтобы не передавать строковую константу? Решение — поместить строку (копию части кода) в переменную. Для удобства назовём такую строку s-строкой, а переменную с этой строкой — s-переменной. Чтобы и в s-переменной не было рекурсии, мы просто исключим из неё фрагмент со значением этой самой переменной. То есть, выглядеть это будет примерно так:

C:

char s[]="char s[]=;";

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

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


Экранирование применить здесь достаточно сложно — символ экранирования надо тоже экранировать и т.д.. Гораздо проще, например, использовать другой вариант кавычек — так, во многих интерпретируемых языках разрешено использование как одинарных, так и двойных кавычек для задания строки, а отличие состоит в том, что можно без проблем использовать одну кавычку в константе, если она ограничивается другими. То есть, код
'"' создаст односимвольную строку с двойной кавычкой, а код "'" — с одиночной. Если использовать этот вариант, удобно задать в начале переменную с какой-либо кавычкой, а затем использовать её при выводе.

Но и этот вариант не универсален: в Си, к примеру, есть лишь один вариант кавычек. Тогда можно использовать другой способ — задавать кавычку кодом символа, печатая символ с таким кодом при выводе.


Следующая проблема — вставка другой строки (или символа с каким-либо кодом) в вывод s-строки. Решение здесь очевидно — брать подстроку s-строки специальной функцией, выводить её, далее выводить то, что надо вставить, затем выводить другую подстроку s-строки. Может показаться, что в Си взятие подстроки для вывода потребует немало кода. Тут нам на помощь придёт мощь функции printf. Так, например, вот варианты кода для различных языков, печатающего часть строки s со второго символа (считая с единицы) по четвёртый включительно:


Python:

print(s[1:4])

Ruby:

print s[1..3]

Perl:

print substr(s,1,2)

C:

printf("%.2s",s+1);

Обычно методы взятия подстроки могут также брать её остаток до конца. Например, напечатаем строку s со второго символа до конца строки (то есть, всю строку кроме первого символа):

Python:

print(s[1:])

Ruby:

print s[1..-1]

Perl:

print substr(s,1)

C:

printf("%s",s+1);

Если такой возможности нет, придётся на место параметра с длиной подстроки поставить заглушку типа «XX», а затем в конце посчитать символы до конца и подставить их вместо «XX» в коде и в s-строке, не изменяя длины различных частей кода. Например, если в длине окажется одна цифра, целесообразно подставить вместо первого икса пробел, ведь если его удалить, длины частей s-строки изменятся и их придётся пересчитывать.

Интерпретируемые языки
Итак, начнём писать квайны, собрав все суждения выше. На Python я написал такой квайн (работает и на 3.x):
q="'";s='q="";s=;print(s[:3]+q+s[3:7]+q+s+q+s[7:])';print(s[:3]+q+s[3:7]+q+s+q+s[7:])

Здесь переменная q используется как переменная, где хранится одинарная кавычка, далее идёт определение s-переменной со всем кодом, кроме самой s-строки. После этого идёт вывод s-переменной со следующими вставками:
1). Одинарная кавычка как значение переменной q;
2). Одинарная кавычка как начало определения s-строки;
3). Сама s-строка (да-да, s-строка вставляется внутри s-строки);
4). Одинарная кавычка как конец определения s-строки.
Примечание. При написании квайнов по данному методу не забывайте копировать все изменения в коде в копию кода в s-строке.

С минимальными изменениями можно получить квайн только для
Python 2.x:
q="'";s='q="";s=;print s[:3]+q+s[3:7]+q+s+q+s[7:]';print s[:3]+q+s[3:7]+q+s+q+s[7:]

Абсолютно аналогичны и квайны на других языках, где мы изменяем лишь некоторые синтаксические особенности:

Ruby:

q="'";s='q="";s=;print s[0..2]+q+s[3..6]+q+s+q+s[7..-1]';print s[0..2]+q+s[3..6]+q+s+q+s[7..-1]

Perl:

$q="'";$s='$q="";$s=;print substr($s,0,4).$q.substr($s,4,5).$q.$s.$q.substr($s,9)'; 
print substr($s,0,4).$q.substr($s,4,5).$q.$s.$q.substr($s,9)

PHP:

<?$q="'";$s='<?$q="";$s=;print substr($s,0,6).$q.substr($s,6,5).$q.$s.$q.substr($s,11);' 
;print substr($s,0,6).$q.substr($s,6,5).$q.$s.$q.substr($s,11);

Компилируемые языки.
Написание квайна на C оказалось чуть более трудной задачей. Здесь я активно использовал коды символов: двойной кавычки — 34, и перевода строки — 13 (он понадобился, чтобы отделить директиву компилятора для включения stdio.h), а также интересный способ взятия подстроки с помощью printf, уже описанный выше.

А вот и сам квайн:


#include <stdio.h>
int main(){const char *s="#include <stdio.h>int main(){const char *s=;
printf(%.18s%c%.25s%c%s%c%.8s%c%.33s%c%s,s,10,s+18,34,s,34,s+43,34,s+51,34,s+84);
return 0;}";printf("%.18s%c%.25s%c%s%c%.8s%c%.33s%c%s",s,10,s+18,34,s,34,s+43,34,s+51,34,s+84); 
return 0;}

Заключение.
Вот и всё. Я написал квайны на большинстве языков, интерпретаторы и компиляторы которых обнаружил на своём компьютере. Думаю, теперь вы и сами напишете подобную программу на своём любимом языке программирования, если я не упомянул его здесь. В качестве упражнения вы также можете написать квайн на таких языках, как Java, C#, Haskell или Pascal. Не бойтесь трудностей — достаточно попробовать, и всё получится! 

На мой взгляд, главное в решении такого рода задачи проявить внимание к деталям и усидчивость, так как легко допустить просчет. 


Ниже приведен листинг решения поставленной задачи.  Скачать можно по ссылке - Download.


#include <stdio.h>
void main(){FILE *f=fopen("output.txt","w");const char *s="#include <stdio.h>void main(){FILE *f=fopen(output.txt,w);const char *s=;fprintf(f,%.18s%c%.26s%c%.10s%c%.1s%c%.1s%c%.16s%c%s%c%.11s%c%.60s%c%s,s,10,s+18,34,s+44,34,s+54,34,s+55,34,s+56,34,s,34,s+72,34,s+83,34,s+143);fclose(f);}";fprintf(f,"%.18s%c%.26s%c%.10s%c%.1s%c%.1s%c%.16s%c%s%c%.11s%c%.60s%c%s",s,10,s+18,34,s+44,34,s+54,34,s+55,34,s+56,34,s,34,s+72,34,s+83,34,s+143);fclose(f);}

 

PHP5. Temporary files

Здесь представлен пример работы со временными файлами, так мне нужно было на удаленном хосте отображать сообщения, доставляемые по udp - протоколу. Конечно, на все это требуются системные ресурсы, но при решении данной задачи было позволительно такое послабление.


<?php ##Temporary files
// Создаем в текущей директории временный файл
$tmp = tempnam(".", "udp");
// Содержимое для временного файла
$content = "Testing...\n";
// "Кладем" данное содержимое во временный файл
file_put_contents($tmp, $content);
// IExplorer для просмотра временного файла
$ie = '"C:\Program Files\Internet Explorer\iexplore.exe" ';
// Путь к временному файлу
$exec = $ie.$tmp;
// Просмотр временного файл User-agent-ом
system($exec);
// Удаляем временный файл
unlink($tmp);
?>

PHP5. Модуль CLI SAPI. Встроенный web-сервер



Официальный сайт PHP - http://www.php.net - гласит:

Начиная с версии PHP 5.4.0 модуль CLI SAPI содержит встроенный web-сервер.

Этот web-сервер предназначен для использования при разработке и не должен использоваться на обычном сервере. 

URI запросы обслуживаются из текущей директории, в которой был запущен PHP, если не используется опция -t для явного указания корневого документа. 

Если URI запроса не указывает на определенный файл, то будет возвращен либо index.php, либо index.html в данной директории. Если не существует ни одного из них, то возвращается 404 код ответа.

Если PHP-файл указывается в командной строке, когда запускается веб-сервер, то он рассматривается как скрипт "маршрутизации" web-сервера. Скрипт выполняется в самом начале после каждого HTTP-запроса. Если этот скрипт возвращает FALSE, то запрашиваемый ресурс возвращается как есть. В противном случае браузеру будет возвращен вывод этого скрипта. 

Если в работе есть необходимость часто работать с php-скриптами, для удобства взаимодействия с ними, например через GUI, можно воспользоваться данным веб-сервером. Намекаю на standalone (и только) приложения, сам запуск такого "сервачка" можно внедрить в сервисы (службы).