ПафНутиЙ-Блог » Статьи » Как защитить свой php-скрипт и привязать его к домену на примере модуля для DLE

Как защитить свой php-скрипт и привязать его к домену на примере модуля для DLE

13.02
Как защитить свой php-скрипт и привязать его к домену на примере модуля для DLE


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

Как то давно я навскидку написал простой модуль вывода информации об аттачменте в любом месте сайта - ShowAttach, но до ума модуль не довёл и публиковать его не стал. Вот этот модуль и возьмём за основу для защиты.
Так же нам понадобятся прямые руки и система PCP-CS от Олега Mofsy.

Что такое pcp-cs


PCP-CS — PHP Code Protect Client-Server. Другими словами клиент-серверное приложение для привязки скриптов к определенным ограничениям (домен, ip сервера и т.д.).

Как работает?


Очень упрощенная схема выглядит так:


Ключевые преимущества


  • Лёгкая интеграция в нужный скрипт. Достаточно вставить код клиента в скрипт и прописать необходимые параметры
  • Встроенная админка для управления серверной частью. Система имеет встроенную административную часть для управления лицензиями, просмотра логов и т.п.
  • Продуманная реализация проверок. Проверки лицензии осуществляются сначала из локального ключа, и если период проверки истёк - данные запрашиваются с сервера проверки, и если сервер проверки недоступен - защищаемый скрипт не перестанет функционировать в течении заданного периода времени.


Установка и настройка серверной части PCP-CS


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

  1. Скачиваем с гитхаба админку по кнопке "Download ZIP". Она уже содержит последнюю версию серверной части pcp-cs, так что на данном этапе больше ничего не потребуется.
  2. Распаковываем папку upload в корень.
  3. Выполняем запрос из sql.sql. Если необходимо сразу завести пользователя, то выполняем запрос:
    INSERT INTO `pcp_users` (`user_id`, `email`, `password`, `name`, `user_group`) VALUES (1, 'admin@admin.ru', 'c3284d0f94606de1fd2af172aba15bf3', 'admin', 1);
    логин и пароль в этом случаи будут admin, admin
  4. Настраиваем конфиг в трёх файлах:
    admin/config/db_config.php - Конфиг БД
    admin/config/config.php - Конфиг админки
    api/config.php - Конфиг pcp-cs
    Такое разделение обусловлено независимостью админки от серверной части pcp-cs.
  5. Всё! Адинка готова к работе. Можно приступать к защите подопытного модуля.



Внедрение клиентской части


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



после успешного создания метода идём в раздел "Лицензии" и добавляе новый лицензионный ключ.



В результате получаем лицезионный ключ, который в дальнейшем можно отдавать покупателю модуля.

Вот теперь можно внедрять непосредственно код клиента!

Сейчас наш подопытный образец модуля (кстати не рекомендую его использовать на живых проетах т.к. он не доработан как следует и будет вызывать повышение нагрузки на бд) выглядит так:
<?php
/*
=============================================================================
Show Attach - модуль вывода информации об аттачменте для для DLE
=============================================================================
Автор: ПафНутиЙ
URL: http://pafnuty.name/
twitter: https://twitter.com/pafnuty_name
google+: http://gplus.to/pafnuty
email: pafnuty10@gmail.com
=============================================================================
*/

if (!defined('DATALIFEENGINE')) {
die("Go fuck yourself!");
}

$cfg = array(
'newsId' => !empty($news_id) ? (int) $news_id : false,
'template' => !empty($template) ? $template : 'showattach/default',
'multiple' => !empty($multiple) ? true : false,
);
if ($cfg['newsId']) {

// Запрос в БД
$row = $db->super_query("SELECT id, news_id, name, onserver, date, dcount FROM " . PREFIX . "_files WHERE news_id = '" . $cfg['newsId'] . "'", $cfg['multiple']);
$tpl->load_template($cfg['template'] . '.tpl');
if (!$cfg['multiple']) {
$rows[] = $row;
} else {
$rows = $row;
}

foreach ($rows as $attachItem) {
if ($rows[0]['id']) {
$onserver = $attachItem['onserver'];
$md5 = md5_file(ROOT_DIR . '/uploads/files/' . $onserver);
$size = formatsize(@filesize(ROOT_DIR . '/uploads/files/' . $onserver));

$tpl->set('{attach_id}', $attachItem['id']);
$tpl->set('{attach_name}', $attachItem['name']);
$tpl->set('{attach_size}', $size);
$tpl->set('{attach_md5}', $md5);

$rowDate = $attachItem['date'];
if (date('Ymd', $rowDate) == date('Ymd', $_TIME)) {
$tpl->set('{attach_date}', $lang['time_heute'] . langdate(", H:i", $rowDate));
} elseif (date('Ymd', $rowDate) == date('Ymd', ($_TIME - 86400))) {
$tpl->set('{attach_date}', $lang['time_gestern'] . langdate(", H:i", $rowDate));
} else {
$tpl->set('{attach_date}', langdate($config['timestamp_active'], $rowDate));
}

$tpl->copy_template = preg_replace_callback("#{attach_date=(.+?)}#i", "formdate", $tpl->copy_template);

$tpl->set('{attach_download}', $attachItem['dcount']);

$tpl->set('[attach]', "");
$tpl->set('[/attach]', "");
$tpl->set_block("'[not-attach](.*?)[/not-attach]'si", "");

if ($user_group[$member_id['user_group']]['allow_files']) {
$tpl->set('[allow-attach]', "");
$tpl->set('[/allow-attach]', "");
$tpl->set_block("'[not-allow-attach](.*?)[/not-allow-attach]'si", "");
} else {
$tpl->set('[not-allow-attach]', "");
$tpl->set('[/not-allow-attach]', "");
$tpl->set_block("'[allow-attach](.*?)[/allow-attach]'si", "");
}

} else {
$tpl->set_block("'[attach](.*?)[/attach]'si", "");
$tpl->set('[not-attach]', "");
$tpl->set('[/not-attach]', "");
}

$tpl->compile('showAttach');
}

$showAttach = $tpl->result['showAttach'];

$tpl->clear();

// Выводим результат работы модуля
echo $showAttach;
}
?>


Вот такой внешний вид вывода данных этим модулем:


Нам необходимо заблокировать работу скрипта, если он используется без лицензии.

Для начала добавим в конфиг модуля параметр key, в который будем передавать полученный лицензионный ключ.
'key' => !empty($key) ? $key : false,

и завернём рабочий код в условие с проверкой этого параметра, а так же добавим отдельное условие для вывода сообщения об отсутствии ключа.
// Если есть ключ и задан ID новости — работаем
if ($cfg['newsId'] && $key) {
......
} elseif (!$key) {
$showAttach = '<span style="color: red;">Не указан лицензионный ключ.</span>';
}
echo $showAttach;

результат:


Добавляем в строку подключения ключ и проверяем:


Теперь нужно добавить проверку введённого ключа с помощью pcp-cs.
  1. Внедряем код клиента в наш модуль. Для экономии ресурсов рекомендую сжать код клиентского класса через любой удобный инструмент. Я использовал сервис . Вставляем полученный код перед основным кодом модуля. Если при проверке выдаёт ошибку:
    Fatal error: Namespace declaration statement has to be the very first statement in the script in

    просто удалите этот код:
    namespace MofsyLicenseClient;

  2. Сразу после кода клиентского класса можно его задействовать и произвести проверку.
    В комментарияк к коду ниже я расписал что и как происходит.
    // Теперь можно запустить проверку лицензии
    $protect = new Protect();

    // Секретный ключ из созданного метода проверки
    $protect->secret_key = 'mqgAqWnSwZZM8YX7BEd9';

    // Куда будем класть локальный (зашифрованный) ключ?
    $protect->local_key_path = ENGINE_DIR . '/data/';

    // Имя и расширение локального ключа
    $protect->local_key_name = 'showattach.lic';

    // Адрес сервера проверки
    $protect->server = 'http://pcp-cs.loc/api.php';

    // Дата релиза модуля (пригодится если лицензия даётся на определённую версию модуля)
    $protect->release_date = '2015-02-10';

    // Ключ активации (лицензионный ключ), тот, который передаётся в параметрах строки подключения модуля
    $protect->activation_key = $key;

    // Сообщения о различных ошибках
    $protect->status_messages = array(
    'status_1' => '<span style="color:green;">Активна</span>',
    'status_2' => '<span style="color:darkblue;">Внимание</span>: срок действия лицензии закончился.',
    'status_3' => '<span style="color:orange;">Внимание</span>: лицензия переиздана. Ожидает повторной активации.',
    'status_4' => '<span style="color:red;">Ошибка</span>: лицензия была приостановлена.',
    'localhost' => '<span style="color:orange;">Активна на localhost</span>: используется локальный компьютер, на реальном сервере произойдет активация, если вы правильно ввели лицензионный ключ активации в настройках.',
    'pending' => '<span style="color:red;">Ошибка</span>: лицензия ожидает рассмотрения.',
    'download_access_expired' => '<span style="color:red;">Ошибка</span>: ключ активации не подходит для установленной версии. Пожалуйста поставьте более старую версию продукта.',
    'missing_activation_key' => '<span style="color:red;">Ошибка</span>: ключ активации не указан.',
    'could_not_obtain_local_key' => '<span style="color:red;">Ошибка</span>: невозможно получить новый локальный ключ.',
    'maximum_delay_period_expired' => '<span style="color:red;">Ошибка</span>: льготный период локального ключа истек.',
    'local_key_tampering' => '<span style="color:red;">Ошибка</span>: локальный лицензионный ключ поврежден или не действителен.',
    'local_key_invalid_for_location' => '<span style="color:red;">Ошибка</span>: локальный ключ не подходит к данному окружению.',
    'missing_license_file' => '<span style="color:red;">Ошибка</span>: создайте следующий пустой файл и папки если их нету:<br />',
    'license_file_not_writable' => '<span style="color:red;">Ошибка</span>: сделайте для записи следующие пути:<br />',
    'invalid_local_key_storage' => '<span style="color:red;">Ошибка</span>: не возможно удалить старый локальный ключ.',
    'could_not_save_local_key' => '<span style="color:red;">Ошибка</span>: не возможно записать новый локальный ключ.',
    'activation_key_string_mismatch' => '<span style="color:red;">Ошибка</span>: локальный ключ не действителен для указанного ключа активации.'

    );

    // Запускаем валидацию лицензии
    $protect->validate();

    $license = false;

    // Если истина, то лицензия в боевом состоянии и можно работать дальше.
    if($protect->status) {
    $license = true;
    }


    Немного доработок в условиях:
    // Если есть ключ и задан ID новости и проверка лицензии прошла успешно — работаем
    if ($cfg['newsId'] && $key && $license) {
    ....
    }
    if (!$key) {
    // Если ключ не передан — надо бы сообщить об этом
    $showAttach = '<span style="color: red;">Не указан лицензионный ключ.</span>';
    }
    if (!$license) {
    // Если лицензия не проверилась - скжем об этом
    $showAttach = (!$protect->errors) ? 'Ошибка лицензии.' : $protect->errors;
    }

    echo $showAttach;


    Если всё сделано правильно — файл с лицензией будет успешно создан в нужной папке, скрипт будет работать., а в админке PCP-CS появится запись о том, где активирован ключ.



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


Вот, собственно, и вся процедура реализации защиты модуля. Остаётся только закодировать код модуля в IonCube и можно продавать или раздавать бесплатно.
Так же не забывайте, что лучше всего реализовать в модуле возможность кеширования и проверять лицензию при отсутствии кеша модуля, так экономятся ресурсы хостинга и ускоряется работа.
После всех действий код модуля должен выглядеть как то так:
<?php
/*
=============================================================================
Show Attach - модуль вывода информации об аттачменте для для DLE
=============================================================================
Автор: ПафНутиЙ
URL: http://pafnuty.name/
twitter: https://twitter.com/pafnuty_name
google+: http://gplus.to/pafnuty
email: pafnuty10@gmail.com
=============================================================================
*/

if (!defined('DATALIFEENGINE')) {
die("Go fuck yourself!");
}

$cfg = array(
'newsId' => !empty($news_id) ? (int) $news_id : false,
'template' => !empty($template) ? $template : 'showattach/default',
'multiple' => !empty($multiple) ? true : false,
'key' => !empty($key) ? $key : false, // Обязательный параметр ключ
);
// Клиентский класс -->

class Protect{ public $status=false; public $errors=false; public $activation_key=''; public $activation_key_expires; public $secret_key='fdfbLhlLgnJDKJklblngkk6krtkghm565678kl78klkUUHtvdfdoghphj'; public $server=''; public $remote_port=80; public $remote_timeout=20; public $local_ua='PHP code protect'; public $use_localhost=false; public $use_expires=true; public $local_key_storage='filesystem'; public $local_key_path='./'; public $local_key_name='license.lic'; public $local_key_transport_order='scf'; public $local_key_delay_period=7; public $local_key_last; public $release_date='2014-10-24'; public $user_name=''; public $status_messages=array('status_1'=>'This activation key is active.','status_2'=>'Error: This activation key has expired.','status_3'=>'Activation key republished. Awaiting reactivation.','status_4'=>'Error: This activation key has been suspended.','localhost'=>'This activation key is active (localhost).','pending'=>'Error: This activation key is pending review.','download_access_expired'=>'Error: This version of the software was released after your download access expired. Please downgrade software or contact support for more information.','missing_activation_key'=>'Error: The activation key variable is empty.','could_not_obtain_local_key'=>'Error: I could not obtain a new local key.','maximum_delay_period_expired'=>'Error: The maximum local key delay period has expired.','local_key_tampering'=>'Error: The local key has been tampered with or is invalid.','local_key_invalid_for_location'=>'Error: The local key is invalid for this location.','missing_license_file'=>'Error: Please create the following file (and directories if they dont exist already): ','license_file_not_writable'=>'Error: Please make the following path writable: ','invalid_local_key_storage'=>'Error: I could not determine the local key storage on clear.','could_not_save_local_key'=>'Error: I could not save the local key.','activation_key_string_mismatch'=>'Error: The local key is invalid for this activation key.'); private $trigger_delay_period; public function __construct(){} public function validate(){if($this->use_localhost&&$this->getIpLocal()&&$this->isWindows()&&!file_exists("{$this->local_key_path}{$this->local_key_name}")){$this->status=true;return $this->errors=$this->status_messages['localhost'];}if(!$this->activation_key){return $this->errors=$this->status_messages['missing_activation_key'];}switch($this->local_key_storage){case 'filesystem':$local_key=$this->readLocalKey();break;default:return $this->errors=$this->status_messages['missing_activation_key'];}$this->trigger_delay_period=$this->status_messages['could_not_obtain_local_key'];if($this->errors==$this->trigger_delay_period&&$this->local_key_delay_period){$delay=$this->processDelayPeriod($this->local_key_last);if($delay['write']){if($this->local_key_storage=='filesystem'){$this->writeLocalKey($delay['local_key'],"{$this->local_key_path}{$this->local_key_name}");}}if($delay['errors']){return $this->errors=$delay['errors'];}$this->errors=false;return $this;}if($this->errors){return $this->errors;}return $this->validateLocalKey($local_key);} private function calcMaxDelay($local_key_expires,$delay){return ((integer)$local_key_expires+((integer)$delay*86400));} private function processDelayPeriod($local_key){$local_key_src=$this->decodeLocalKey($local_key);$parts=$this->splitLocalKey($local_key_src);$key_data=unserialize($parts[0]);$local_key_expires=(integer)$key_data['local_key_expires'];unset($parts,$key_data);$write_new_key=false;$parts=explode("nn",$local_key);$local_key=$parts[0];foreach($local_key_delay_period=explode(',',$this->local_key_delay_period) as $key=>$delay){if(!$key){$local_key.="n";}if($this->calcMaxDelay($local_key_expires,$delay)>time()){continue;}$local_key.="n{$delay}";$write_new_key=true;}if(time()>$this->calcMaxDelay($local_key_expires,array_pop($local_key_delay_period))){return array('write'=>false,'local_key'=>'','errors'=>$this->status_messages['maximum_delay_period_expired']);}return array('write'=>$write_new_key,'local_key'=>$local_key,'errors'=>false);} private function inDelayPeriod($local_key,$local_key_expires){$delay=$this->splitLocalKey($local_key,"nn");if(!isset($delay[1])){return -1;}return (integer)($this->calcMaxDelay($local_key_expires,array_pop(explode("n",$delay[1])))-time());} private function decodeLocalKey($local_key){return base64_decode(str_replace("n",'',urldecode($local_key)));} private function splitLocalKey($local_key,$token='{protect}'){return explode($token,$local_key);} private function validateAccess($key,$valid_accesses){return in_array($key,(array)$valid_accesses);} private function wildcardIp($key){$octets=explode('.',$key);array_pop($octets);$ip_range[]=implode('.',$octets).'.*';array_pop($octets);$ip_range[]=implode('.',$octets).'.*';array_pop($octets);$ip_range[]=implode('.',$octets).'.*';return $ip_range;} private function wildcardServerHostname($key){$hostname=explode('.',$key);unset($hostname[0]);$hostname=(!isset($hostname[1]))?array($key):$hostname;return '*.'.implode('.',$hostname);} private function extractAccessSet($instances,$enforce){foreach($instances as $key=>$instance){if($key!=$enforce){continue;}return $instance;}return array();} private function validateLocalKey($local_key){$local_key_src=$this->decodeLocalKey($local_key);$parts=$this->splitLocalKey($local_key_src);if(!isset($parts[1])){return $this->errors=$this->status_messages['local_key_tampering'];}if(md5((string)$this->secret_key.(string)$parts[0])!=$parts[1]){return $this->errors=$this->status_messages['local_key_tampering'];}unset($this->secret_key);$key_data=unserialize($parts[0]);$instance=$key_data['instance'];unset($key_data['instance']);$enforce=$key_data['enforce'];unset($key_data['enforce']);$this->user_name=$key_data['user_name'];if((string)$key_data['activation_key_expires']=='never'){$this->activation_key_expires=0;}else {$this->activation_key_expires=(integer)$key_data['activation_key_expires'];}if((string)$key_data['activation_key']!=(string)$this->activation_key){return $this->errors=$this->status_messages['activation_key_string_mismatch'];}if((integer)$key_data['status']!=1&&(integer)$key_data['status']!=2){return $this->errors=$this->status_messages['status_'.$key_data['status']];}if($this->use_expires==false&&(string)$key_data['activation_key_expires']!='never'&&(integer)$key_data['activation_key_expires']<time()){return $this->errors=$this->status_messages['status_2'];}if($this->use_expires==false&&(string)$key_data['local_key_expires']!='never'&&(integer)$key_data['local_key_expires']<time()){if($this->inDelayPeriod($local_key,$key_data['local_key_expires'])<0){$this->clearLocalKey();return $this->validate();}}if($this->use_expires==true&&(string)$key_data['activation_key_expires']!='never'&&(integer)$key_data['activation_key_expires']<strtotime($this->release_date)){return $this->errors=$this->status_messages['download_access_expired'];}if($this->use_expires==true&&(string)$key_data['local_key_expires']!='never'&&(integer)$key_data['local_key_expires']<time()&&(integer)$key_data['activation_key_expires']>(integer)$key_data['local_key_expires']+604800){if($this->inDelayPeriod($local_key,$key_data['local_key_expires'])<0){$this->clearLocalKey();return $this->validate();}}$conflicts=array();$access_details=$this->accessDetails();foreach((array)$enforce as $key){$valid_accesses=$this->extractAccessSet($instance,$key);if(!$this->validateAccess($access_details[$key],$valid_accesses)){$conflicts[$key]=true;if(in_array($key,array('ip','server_ip'))){foreach($this->wildcardIp($access_details[$key]) as $ip){if($this->validateAccess($ip,$valid_accesses)){unset($conflicts[$key]);break;}}}elseif(in_array($key,array('domain'))){if(isset($key_data['domain_wildcard'])){if($key_data['domain_wildcard']==1&&preg_match("/".$valid_accesses[0]."z/i",$access_details[$key])){$access_details[$key]='*.'.$valid_accesses[0];}if($key_data['domain_wildcard']==2){$exp_domain=explode('.',$valid_accesses[0]);$exp_domain=$exp_domain[0];if(preg_match("/".$exp_domain."/i",$access_details[$key])){$access_details[$key]='*.'.$valid_accesses[0].'.*';}}if($key_data['domain_wildcard']==3){$exp_domain=explode('.',$valid_accesses[0]);$exp_domain=$exp_domain[0];if(preg_match("/A".$exp_domain."/i",$access_details[$key])){$access_details[$key]=$valid_accesses[0].'.*';}}}if($this->validateAccess($access_details[$key],$valid_accesses)){unset($conflicts[$key]);}}elseif(in_array($key,array('server_hostname'))){if($this->validateAccess($this->wildcardServerHostname($access_details[$key]),$valid_accesses)){unset($conflicts[$key]);}}}}if(!empty($conflicts)){return $this->errors=$this->status_messages['local_key_invalid_for_location'];}$this->errors=$this->status_messages['status_1'];return $this->status=true;} public function readLocalKey(){if(!is_dir($this->local_key_path)){mkdir($this->local_key_path,0755,true);}if(!file_exists($path="{$this->local_key_path}{$this->local_key_name}")){$f=@fopen($path,'w');if(!$f){return $this->errors=$this->status_messages['missing_license_file'].$path;}else {fwrite($f,'');fclose($f);}}if(!is_writable($path)){@chmod($path,0777);if(!is_writable($path)){@chmod("$path",0755);if(!is_writable($path)){return $this->errors=$this->status_messages['license_file_not_writable'].$path;}}}if(!$local_key=@file_get_contents($path)){$local_key=$this->getServerLocalKey();if($this->errors){return $this->errors;}$this->writeLocalKey(urldecode($local_key),$path);}return $this->local_key_last=$local_key;} public function clearLocalKey(){if($this->local_key_storage=='filesystem'){$this->writeLocalKey('',"{$this->local_key_path}{$this->local_key_name}");}else {$this->errors=$this->status_messages['invalid_local_key_storage'];}} public function writeLocalKey($local_key,$path){$fp=@fopen($path,'w');if(!$fp){return $this->errors=$this->status_messages['could_not_save_local_key'];}@fwrite($fp,$local_key);@fclose($fp);return true;} private function getServerLocalKey(){$query_string='activation_key='.urlencode($this->activation_key).'&';$query_string.=http_build_query($this->accessDetails());if($this->errors){return false;}$priority=$this->local_key_transport_order;$result=false;while(strlen($priority)){$use=substr($priority,0,1);if($use=='s'){if($result=$this->useFsockopen($this->server,$query_string)){break;}}if($use=='c'){if($result=$this->useCurl($this->server,$query_string)){break;}}if($use=='f'){if($result=$this->useFopen($this->server,$query_string)){break;}}$priority=substr($priority,1);}if(!$result){$this->errors=$this->status_messages['could_not_obtain_local_key'];return false;}if(substr($result,0,7)=='Invalid'){$this->errors=str_replace('Invalid','Error',$result);return false;}if(substr($result,0,5)=='Error'){$this->errors=$result;return false;}return $result;} private function accessDetails(){$access_details=array();if(function_exists('phpinfo')){ob_start();phpinfo();$phpinfo=ob_get_contents();ob_end_clean();$list=strip_tags($phpinfo);$access_details['domain']=$this->scrapePhpInfo($list,'HTTP_HOST');$access_details['ip']=$this->scrapePhpInfo($list,'SERVER_ADDR');$access_details['directory']=$this->scrapePhpInfo($list,'SCRIPT_FILENAME');$access_details['server_hostname']=$this->scrapePhpInfo($list,'System');$access_details['server_ip']=@gethostbyname($access_details['server_hostname']);}$access_details['domain']=($access_details['domain'])?$access_details['domain']:$_SERVER['HTTP_HOST'];$access_details['ip']=($access_details['ip'])?$access_details['ip']:$this->serverAddr();$access_details['directory']=($access_details['directory'])?$access_details['directory']:$this->pathTranslated();$access_details['server_hostname']=($access_details['server_hostname'])?$access_details['server_hostname']:@gethostbyaddr($access_details['ip']);$access_details['server_hostname']=($access_details['server_hostname'])?$access_details['server_hostname']:'Unknown';$access_details['server_ip']=($access_details['server_ip'])?$access_details['server_ip']:@gethostbyaddr($access_details['ip']);$access_details['server_ip']=($access_details['server_ip'])?$access_details['server_ip']:'Unknown';foreach($access_details as $key=>$value){$access_details[$key]=($access_details[$key])?$access_details[$key]:'Unknown';}return $access_details;} private function pathTranslated(){$option=array('PATH_TRANSLATED','ORIG_PATH_TRANSLATED','SCRIPT_FILENAME','DOCUMENT_ROOT','APPL_PHYSICAL_PATH');foreach($option as $key){if(!isset($_SERVER[$key])||strlen(trim($_SERVER[$key]))<=0){continue;}if($this->isWindows()&&strpos($_SERVER[$key],'')){return @substr($_SERVER[$key],0,@strrpos($_SERVER[$key],''));}return @substr($_SERVER[$key],0,@strrpos($_SERVER[$key],'/'));}return false;} private function serverAddr(){$options=array('SERVER_ADDR','LOCAL_ADDR');foreach($options as $key){if(isset($_SERVER[$key])){return $_SERVER[$key];}}return false;} private function scrapePhpInfo($all,$target){$all=explode($target,$all);if(count($all)<2){return false;}$all=explode("n",$all[1]);$all=trim($all[0]);if($target=='System'){$all=explode(" ",$all);$all=trim($all[(strtolower($all[0])=='windows'&&strtolower($all[1])=='nt')?2:1]);}if($target=='SCRIPT_FILENAME'){$slash=($this->isWindows()?'':'/');$all=explode($slash,$all);array_pop($all);$all=implode($slash,$all);}if(substr($all,1,1)==']'){return false;}return $all;} private function useFsockopen($url,$query_string){if(!function_exists('fsockopen')){return false;}$url=parse_url($url);$fp=@fsockopen($url['host'],$this->remote_port,$errno,$errstr,$this->remote_timeout);if(!$fp){return false;}$header="POST {$url['path']} HTTP/1.0rn";$header.="Host: {$url['host']}rn";$header.="Content-type: application/x-www-form-urlencodedrn";$header.="User-Agent: ".$this->local_ua."rn";$header.="Content-length: ".@strlen($query_string)."rn";$header.="Connection: closernrn";$header.=$query_string;$result=false;fputs($fp,$header);while(!feof($fp)){$result.=fgets($fp,1024);}fclose($fp);if(strpos($result,'200')===false){return false;}$result=explode("rnrn",$result,2);if(!$result[1]){return false;}return $result[1];} private function useCurl($url,$query_string){if(!function_exists('curl_init')){return false;}$curl=curl_init();$header[0]="Accept: text/xml,application/xml,application/xhtml+xml,";$header[0].="text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";$header[]="Cache-Control: max-age=0";$header[]="Connection: keep-alive";$header[]="Keep-Alive: 300";$header[]="Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";$header[]="Accept-Language: en-us,en;q=0.5";$header[]="Pragma: ";curl_setopt($curl,CURLOPT_URL,$url);curl_setopt($curl,CURLOPT_USERAGENT,$this->local_ua);curl_setopt($curl,CURLOPT_HTTPHEADER,$header);curl_setopt($curl,CURLOPT_ENCODING,'gzip,deflate');curl_setopt($curl,CURLOPT_AUTOREFERER,true);curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);curl_setopt($curl,CURLOPT_POST,1);curl_setopt($curl,CURLOPT_POSTFIELDS,$query_string);curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,0);curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,0);curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,$this->remote_timeout);curl_setopt($curl,CURLOPT_TIMEOUT,$this->remote_timeout);$result=curl_exec($curl);$info=curl_getinfo($curl);curl_close($curl);if((integer)$info['http_code']!=200){return false;}return $result;} private function useFopen($url,$query_string){if(!function_exists('file_get_contents')||!ini_get('allow_url_fopen')||!extension_loaded('openssl')){return false;}$stream=array('http'=>array('method'=>'POST','header'=>"Content-type: application/x-www-form-urlencodedrnUser-Agent: ".$this->local_ua,'content'=>$query_string));$context=null;$context=stream_context_create($stream);return @file_get_contents($url,false,$context);} private function isWindows(){return (strtolower(substr(php_uname(),0,7))=='windows');} private function getIpLocal(){$local_ip='';if(function_exists('phpinfo')){ob_start();phpinfo();$phpinfo=ob_get_contents();ob_end_clean();$list=strip_tags($phpinfo);$local_ip=$this->scrapePhpInfo($list,'SERVER_ADDR');}$local_ip=($local_ip)?$local_ip:$this->serverAddr();if($local_ip=='127.0.0.1')return true;return false;}}
// <-- клиентский класс

// Теперь можно запустить проверку лицензии
$protect = new Protect();

// Секретный ключ из созданного метода проверки
$protect->secret_key = 'mqgAqWnSwZZM8YX7BEd9';

// Куда будем класть локальный (зашифрованный) ключ?
$protect->local_key_path = ENGINE_DIR . '/data/';

// Имя и расширение локального ключа
$protect->local_key_name = 'showattach.lic';

// Адрес сервера проверки
$protect->server = 'http://pcp-cs.loc/api.php';

// Дата релиза модуля (пригодится если лицензия даётся на определённую версию модуля)
$protect->release_date = '2015-02-10';

// Ключ активации (лицензионный ключ), тот, который передаётся в параметрах строки подключения модуля
$protect->activation_key = $key;

// Сообщения о различных ошибках
$protect->status_messages = array(
'status_1' => '<span style="color:green;">Активна</span>',
'status_2' => '<span style="color:darkblue;">Внимание</span>: срок действия лицензии закончился.',
'status_3' => '<span style="color:orange;">Внимание</span>: лицензия переиздана. Ожидает повторной активации.',
'status_4' => '<span style="color:red;">Ошибка</span>: лицензия была приостановлена.',
'localhost' => '<span style="color:orange;">Активна на localhost</span>: используется локальный компьютер, на реальном сервере произойдет активация, если вы правильно ввели лицензионный ключ активации в настройках.',
'pending' => '<span style="color:red;">Ошибка</span>: лицензия ожидает рассмотрения.',
'download_access_expired' => '<span style="color:red;">Ошибка</span>: ключ активации не подходит для установленной версии. Пожалуйста поставьте более старую версию продукта.',
'missing_activation_key' => '<span style="color:red;">Ошибка</span>: ключ активации не указан.',
'could_not_obtain_local_key' => '<span style="color:red;">Ошибка</span>: невозможно получить новый локальный ключ.',
'maximum_delay_period_expired' => '<span style="color:red;">Ошибка</span>: льготный период локального ключа истек.',
'local_key_tampering' => '<span style="color:red;">Ошибка</span>: локальный лицензионный ключ поврежден или не действителен.',
'local_key_invalid_for_location' => '<span style="color:red;">Ошибка</span>: локальный ключ не подходит к данному окружению.',
'missing_license_file' => '<span style="color:red;">Ошибка</span>: создайте следующий пустой файл и папки если их нету:<br />',
'license_file_not_writable' => '<span style="color:red;">Ошибка</span>: сделайте для записи следующие пути:<br />',
'invalid_local_key_storage' => '<span style="color:red;">Ошибка</span>: не возможно удалить старый локальный ключ.',
'could_not_save_local_key' => '<span style="color:red;">Ошибка</span>: не возможно записать новый локальный ключ.',
'activation_key_string_mismatch' => '<span style="color:red;">Ошибка</span>: локальный ключ не действителен для указанного ключа активации.'

);

// Запускаем валидацию лицензии
$protect->validate();

$license = false;

// Если истина, то лицензия в боевом состоянии и можно работать дальше.
if($protect->status) {
$license = true;
}

// Если есть ключ и задан ID новости и проверка лицензии прошла успешно — работаем
if ($cfg['newsId'] && $key && $license) {

// Запрос в БД
$row = $db->super_query("SELECT id, news_id, name, onserver, date, dcount FROM " . PREFIX . "_files WHERE news_id = '" . $cfg['newsId'] . "'", $cfg['multiple']);
$tpl->load_template($cfg['template'] . '.tpl');
if (!$cfg['multiple']) {
$rows[] = $row;
} else {
$rows = $row;
}

foreach ($rows as $attachItem) {
if ($rows[0]['id']) {
$onserver = $attachItem['onserver'];
$md5 = md5_file(ROOT_DIR . '/uploads/files/' . $onserver);
$size = formatsize(@filesize(ROOT_DIR . '/uploads/files/' . $onserver));

$tpl->set('{attach_id}', $attachItem['id']);
$tpl->set('{attach_name}', $attachItem['name']);
$tpl->set('{attach_size}', $size);
$tpl->set('{attach_md5}', $md5);

$rowDate = $attachItem['date'];
if (date('Ymd', $rowDate) == date('Ymd', $_TIME)) {
$tpl->set('{attach_date}', $lang['time_heute'] . langdate(", H:i", $rowDate));
} elseif (date('Ymd', $rowDate) == date('Ymd', ($_TIME - 86400))) {
$tpl->set('{attach_date}', $lang['time_gestern'] . langdate(", H:i", $rowDate));
} else {
$tpl->set('{attach_date}', langdate($config['timestamp_active'], $rowDate));
}

$tpl->copy_template = preg_replace_callback("#{attach_date=(.+?)}#i", "formdate", $tpl->copy_template);

$tpl->set('{attach_download}', $attachItem['dcount']);

$tpl->set('[attach]', "");
$tpl->set('[/attach]', "");
$tpl->set_block("'[not-attach](.*?)[/not-attach]'si", "");

if ($user_group[$member_id['user_group']]['allow_files']) {
$tpl->set('[allow-attach]', "");
$tpl->set('[/allow-attach]', "");
$tpl->set_block("'[not-allow-attach](.*?)[/not-allow-attach]'si", "");
} else {
$tpl->set('[not-allow-attach]', "");
$tpl->set('[/not-allow-attach]', "");
$tpl->set_block("'[allow-attach](.*?)[/allow-attach]'si", "");
}

} else {
$tpl->set_block("'[attach](.*?)[/attach]'si", "");
$tpl->set('[not-attach]', "");
$tpl->set('[/not-attach]', "");
}

$tpl->compile('showAttach');
}

$showAttach = $tpl->result['showAttach'];

$tpl->clear();

// Выводим результат работы модуля
}
if (!$key) {
// Если ключ не передан — надо бы сообщить об этом
$showAttach = '<span style="color: red;">Не указан лицензионный ключ.</span>';
}
if (!$license) {
// Если лицензия не проверилась - скжем об этом
$showAttach = (!$protect->errors) ? 'Ошибка лицензии.' : $protect->errors;
}

echo $showAttach;
?>


В качестве дополнения


Код pcp-cs очень хорошо прокомментирован и для реализации различных вариантов проверки достаточно почитать что там написано. К примеру для использования модуля на локалке без активации достаточно прописать параметр:
$protect->use_localhost = true;

Ну и конечно же если у вас есть идеи и пожелания - мы с Олегом будем всегда рады видеть эти пожелания на гитхабе

Комментарии

ПафНутиЙ
ПафНутиЙ 14 сентября 2015 19:03
#31
Цитата: chapser
Этот скрипт бесполезен.

Да, вы совершенно правы, он не совместим с кривыми руками.
savvato
savvato 15 сентября 2015 13:26
#32
Работает без локальной лицензии(ключа)? И что когда сервер лицензий лежит делать?
ПафНутиЙ
ПафНутиЙ 15 сентября 2015 13:35
#33
Цитата: savvato
Работает без локальной лицензии(ключа)?

А должен?
Цитата: savvato
И что когда сервер лицензий лежит делать?

Описано в самом начале статьи.
savvato
savvato 15 сентября 2015 13:44
#34
Та предыдущий комент касаемо phpmylicense.com касается. Не касаемо Вашего продукта. У Вас норм продумано в этом плане)))
Lena
Lena 17 сентября 2015 19:13
#35
Здравствуйте! Уважаемый Пафнутий, звините меня что я тут вообще не к месту со своим вопросом.
Но мне сказали что Вы все знаете про скрипты и т.п.
Вы не могли бы подсказать какой плагин исрлдбзуется на этом сайте https://weboster.ru/rules.html и где его можно скачать.
Только пожалуйста не ругайтесь...я только начала пытаться сделать свой сайт и тольком ни чего не знаю:)
ПафНутиЙ
ПафНутиЙ 17 сентября 2015 19:42
#36
Вас обманули.
Я очень мало знаю про скрипты и т.п.
Но вы правы — ваш вопрос не к месту, задайте его на dle-faq.ru если он относится к DLE, или на stackowerflow или на toster.ru
maksodintsov
maksodintsov 22 октября 2015 13:04
#37
"я только начала пытаться сделать свой сайт и тольком ни чего не знаю"
ха! Видимо только начала не только сайт свой создавать..а скорей всего только начала В ШКОЛУ ХОДИТЬ...("плагин исрлдбзуется на этом сайте https:/...")
ComBO
ComBO 26 октября 2015 17:39
#38
ПафНутиЙ,
я все сделал как нужно но у меня выдает такую ошибку)) Ошибка: локальный лицензионный ключ поврежден или не действителен. )) помоги ))
ПафНутиЙ
ПафНутиЙ 26 октября 2015 21:45
#39
Клиентская часть переехала сюда, напишите тиккет, очень желательно с примером или подробным описанием ошибки.
Archangel
Archangel 22 декабря 2015 12:54
#40
Хотел попробовать установить арматуру, но на гите нету sql для системы, как в pcp. _ttps://github.com/Armature/Server

Нету ли пустой базы от арматурки ?
ПафНутиЙ
ПафНутиЙ 27 декабря 2015 17:22
#41
Задайте вопрос в репозитории, я пока не готов на него ответить.
wolf
wolf 10 февраля 2016 21:47
#42
здравствуйте подскажите в какой файл клиент должен ввезти лицензионный ключ?
ПафНутиЙ
ПафНутиЙ 10 февраля 2016 21:48
#43
Это полностью зависит от разработчика.
wolf
wolf 10 февраля 2016 21:53
#44
ПафНутиЙ,
спасибо за оперативный ответ, smile а в вашей админке можно продливать лицензионный ключ? или там только постоянно нужно её создавать заного? если можно продливать то подскажите как, заранее спасибо
ПафНутиЙ
ПафНутиЙ 10 февраля 2016 22:04
#45
Если необходимо продление - логичнее создать новый ключ. или не ограничивать срок его действия.
wolf
wolf 10 февраля 2016 22:15
#46
ПафНутиЙ,
smile спасибо) тогда легче сделать кнопку удаления (ну это я сделаю), чтоб старый ключ удалять, а новый создавать)
wolf
wolf 12 февраля 2016 14:58
#47
ПафНутиЙ,
у вас хороший пример приведен, ну тут все в одном файле, а если лицензию нужно сделать в двух файлах? получается я делаю все как у вас описано только вставляю клиентский класс в install.php, затем вывожу из класса
$key = $_POST["key"];
$protect->activation_key = $_POST["key"];

и из формы html отправляю Post запросом (в этом же файле введенный пользователем ключ), чтобы он записался в $protect->activation_key =''; ну это все в одном файле, а проверку ключа мне нужно сделать в файле index.php, как мне дать понять коду что ключ вписан и отправить его в файл index.php? в index.php будет так
if ($key && $license) {
работаем
} else {
выключаем
}
ну в файле index.php будет не определены переменные $key && $license как мне их определить в index.php?
wolf
wolf 12 февраля 2016 14:59
#48
помогите пожалуйста
ПафНутиЙ
ПафНутиЙ 12 февраля 2016 15:36
#49
Записывайте ключ в конфиг, читайте из конфига.
wolf
wolf 12 февраля 2016 15:42
#50
Цитата: ПафНутиЙ
Записывайте ключ в конфиг, читайте из конфига.

а можете пример привести как в коде это сделать?
wolf
wolf 12 февраля 2016 15:53
#51
я вот читал вы пишите
Для начала добавим в конфиг модуля параметр key, в который будем передавать полученный лицензионный ключ.

'key' => !empty($key) ? $key : false,
только не совсем понятно как ключ в этот код передать
wolf
wolf 12 февраля 2016 16:53
#52
ПафНутиЙ,
все спасибо я разобрался)))
wolf
wolf 12 февраля 2016 18:38
#53
можно ли как то вывести? Ваша лицензия действительна до:
wolf
wolf 13 февраля 2016 12:56
#54
а если будет несколько модулей, то нужно для каждого модуля разный секретный ключ?
quiman
quiman 3 июня 2016 13:57
#55
Здравствуйте.
Нарыл статью в интернете.
Хочу поставить себе, но у меня высвечивает ошибку -
Fatal error: SafeMySQL: 2002 Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2). 

Можете помочь, что тут может быть не так?
ПафНутиЙ
ПафНутиЙ 4 июня 2016 00:04
#56
скрипт не может подсоединиться к серверу. погуглите, проблема известная.
stg
stg 16 августа 2016 09:30
#57
Большинство сайтов это shared-хостинг и на одном IP размещено несколько сотен или тысяч сайтов, и много IP занесено в бан на хостингах, не будет ли банить хостинг где установлена серверная часть запросы при попытке получить лицензионный ключ?
ПафНутиЙ
ПафНутиЙ 16 августа 2016 09:39
#58
Я бы в здравом уме не сталбы размещать серверную часть на shared хостинге.
Купите VPS, поставьте туда https://vestacp.com/ и это буде намного эффективнее shared-хостинга
Ойбек
Ойбек 29 сентября 2016 07:23
#59
Добрый день! Нужна помощь мне..
Скачал исходник клиента там были example.php и clien.class.php всё настроил, вот теперь как в example.php скрыть свой код, если ключь не активен, а после того как активен, пусть выводится нужный мне код:
<?php
/**
 * PHP code protect
 *
 * @link          https://github.com/Mofsy/pcp-cs
 * @author        Oleg Budrin <ru.mofsy@yandex.ru>
 * @copyright     Copyright (c) 2013-2015, Oleg Budrin (Mofsy)
 */

$time_start = microtime(true);
include_once(__DIR__ . DIRECTORY_SEPARATOR . 'client.class.php');

/**
 * Создаем экземпляр класса   Секретный ключь настроен в client.class.php
 */
$protect = new MofsyLicenseClientProtect();

/**
 * Указываем директорию с правами на запись.
 * В эту директорию будет скачиваться файл локального ключа с сервера.
 */
$protect->local_key_path = './';

/**
 * Указываем название файла в котором будет храниться локальный ключ.
 */
$protect->local_key_name = 'license.lic';

/**
 * Указываем полный путь до сервера лицензий.
 */
$protect->server = 'https://сюда URL сайта где стоит админка/api.php';

/**
 * Указываем ключ активации, например из конфигурации.
 */
$protect->activation_key = 'сюда активационный ключь';

/**
 * Указываем дату релиза скрипта
 */
$protect->release_date = '2014-10-02';

/**
 * Устанавливаем локализацию статусов и ошибок
 */
$protect->status_messages = array(
    'status_1'                       => '<span style="color:green;">Активна</span>',
    'status_2'                       => '<span style="color:darkblue;">Внимание</span>: срок действия лицензии закончился.',
    'status_3'                       => '<span style="color:orange;">Внимание</span>: лицензия переиздана. Ожидает повторной активации.',
    'status_4'                       => '<span style="color:red;">Ошибка</span>: лицензия была приостановлена.',
    'localhost'                      => '<span style="color:orange;">Активна на localhost</span>: используется локальный компьютер, на реальном сервере произойдет активация, если вы правильно ввели лицензионный ключ активации в настройках.',
    'pending'                        => '<span style="color:red;">Ошибка</span>: лицензия ожидает рассмотрения.',
    'download_access_expired'        => '<span style="color:red;">Ошибка</span>: ключ активации не подходит для установленной версии. Пожалуйста поставьте более старую версию продукта.',
    'missing_activation_key'         => '<span style="color:red;">Ошибка</span>: ключ активации не указан.',
    'could_not_obtain_local_key'     => '<span style="color:red;">Ошибка</span>: невозможно получить новый локальный ключ.',
    'maximum_delay_period_expired'   => '<span style="color:red;">Ошибка</span>: льготный период локального ключа истек.',
    'local_key_tampering'            => '<span style="color:red;">Ошибка</span>: локальный лицензионный ключ поврежден или не действителен.',
    'local_key_invalid_for_location' => '<span style="color:red;">Ошибка</span>: локальный ключ не подходит к данному окружению.',
    'missing_license_file'           => '<span style="color:red;">Ошибка</span>: создайте следующий пустой файл и папки если их нету:<br />',
    'license_file_not_writable'      => '<span style="color:red;">Ошибка</span>: сделайте для записи следующие пути:<br />',
    'invalid_local_key_storage'      => '<span style="color:red;">Ошибка</span>: не возможно удалить старый локальный ключ.',
    'could_not_save_local_key'       => '<span style="color:red;">Ошибка</span>: не возможно записать новый локальный ключ.',
    'activation_key_string_mismatch' => '<span style="color:red;">Ошибка</span>: локальный ключ не действителен для указанного ключа активации.'
);

/**
 * Запускаем валидацию
 */
$protect->validate();

/**
 * Если истина, то лицензия в боевом состоянии
 */
if ($protect->status) {
    $license = true;
}

/**
 * Можно вывести текстовый статус лицензии
 *
 * NOTE: например в панели скрипта или в лог, что бы знать в каком состоянии находится лицензия.
 */
echo 'Статус: ' . $protect->errors;

/**
 * Так же можно вывести имя (логин), на которое выдана лицензия
 */
echo '<br />Имя, на которое выдан ключ активации: ' . $protect->user_name;

/**
 * Так же можно вывести дату окончания лицензии
 */
if(is_numeric($protect->activation_key_expires) && $protect->activation_key_expires > 0) {
    echo '<br />Ключ действует до ' . date('j F Y, H:i', $protect->activation_key_expires);
} else {
    echo '<br />Ключ действует вечно';
}

$time_end = microtime(true);
$time = $time_end - $time_start;

echo "<br /> Выполнялось $time секундn";

Это код для вскрытия и открытия после активации
print file_get_contents('http://..../что_то_тут.php');
ПафНутиЙ
ПафНутиЙ 29 сентября 2016 13:07
#60
if($license){лицензия активна} else {лицензия не активна}

Добавить комментарий

Информация

Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.

Комментировать могут только зарегистрированные пользователи