Архив рубрики: PHP

Как завершить скрипты по таймауту

Задача: ряд скриптов иногда «зависают». Есть два варианта — переделать скрипт, чтобы не «зависал». Не всегда возможно. Второй вариант: отслеживать время работы скрипта, и по какому то предельному значению времени выполнения — убивать. Например так:

#!/usr/local/bin/php
<?php
$timeout=100; // время после которого скрипт считаем зависшим
$res=`ps -ax | grep sos | awk '{print $1,$4}'`;

$resa=explode("\n",$res);

foreach ($resa as $value) {
 if ($value!=""){
  $va=explode(" ",$value);
  $pid=$va[0];
  $timea=explode(":",$va[1]);
    if (isset($timea[1])==true){
      $time=$timea[0];
      echo "PID: $pid, TIME: $time\n";
      if ($time>$timeout){
       `kill $pid`;
      };
    };
  };
};
?>

Добавляем данные в таблицу Google Sheeet при помощи PHP

Руководство от Гугла для ознакомления. Делано собственно по нему.

1) Включаем в своем аккаунте доступ к Google Sheets API. Сделать это можно прямо на странице «Руководство от Гугла«:

Получаем ID, секрет и файл credentials.json который сохраняем туда, где будет лежать основной скрипт

2) При помощи composer добавляем необходимые библиотеки

composer require google/apiclient:^2.0
composer update

3) Создаем таблицу в гуглодокументах и узнаем её ID — можно взять прямо из URL. Так-же даем доступ «всем вподряд по ссылке»

4) Создаем следующего вида файл:

<?php
require 'vendor/autoload.php';

if (php_sapi_name() != 'cli') {
    throw new Exception('This application must be run on the command line.');
}

/**
 * Returns an authorized API client.
 * @return Google_Client the authorized client object
 */
function getClient(){
    $client = new Google_Client();
    $client->setApplicationName('Google Sheets API PHP Quickstart');
    $client->setScopes(Google_Service_Sheets::SPREADSHEETS);
    $client->setAuthConfig('credentials.json');
    $client->setAccessType('offline');
    $client->setPrompt('select_account consent');

    // Load previously authorized token from a file, if it exists.
    // The file token.json stores the user's access and refresh tokens, and is
    // created automatically when the authorization flow completes for the first
    // time.
    $tokenPath = 'token.json';
    if (file_exists($tokenPath)) {
        $accessToken = json_decode(file_get_contents($tokenPath), true);
        $client->setAccessToken($accessToken);
    }

    // If there is no previous token or it's expired.
    if ($client->isAccessTokenExpired()) {
        // Refresh the token if possible, else fetch a new one.
        if ($client->getRefreshToken()) {
            $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
        } else {
            // Request authorization from the user.
            $authUrl = $client->createAuthUrl();
            printf("Open the following link in your browser:\n%s\n", $authUrl);
            print 'Enter verification code: ';
            $authCode = trim(fgets(STDIN));

            // Exchange authorization code for an access token.
            $accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
            $client->setAccessToken($accessToken);

            // Check to see if there was an error.
            if (array_key_exists('error', $accessToken)) {
                throw new Exception(join(', ', $accessToken));
            }
        }
        // Save the token to a file.
        if (!file_exists(dirname($tokenPath))) {
            mkdir(dirname($tokenPath), 0700, true);
        }
        file_put_contents($tokenPath, json_encode($client->getAccessToken()));
    }
    return $client;
}




// Get the API client and construct the service object.
$client = getClient();
$service = new Google_Service_Sheets($client);

// Prints the names and majors of students in a sample spreadsheet:
// https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
$spreadsheetId = 'аыукаыука-HW95_v_xwJ-U_L2Xc';
$range = 'Sheets1!A2:A';
$response = $service->spreadsheets_values->get($spreadsheetId, $range);
$values = $response->getValues();
var_dump($values);
if (empty($values)) {
    print "No data found.\n";
} else {
    print "Name, Major:\n";
    foreach ($values as $row) {
        // Print columns A and E, which correspond to indices 0 and 4.
        printf("%s\n", $row[0]);
    }
};
$values = [
	["2016-02-12", "5453 543543", "=C2+C3"],
	["2017-02-12", "5453 543543", "=C2+C3"],
	["2018-02-12", "5453 543543", "=C2+C3"],
];
$body    = new Google_Service_Sheets_ValueRange( [ 'values' => $values ] );
 
// valueInputOption - определяет способ интерпретации входных данных
// https://developers.google.com/sheets/api/reference/rest/v4/ValueInputOption
// RAW | USER_ENTERED
$options = array( 'valueInputOption' => 'RAW' );
 
$service->spreadsheets_values->update( $spreadsheetId, 'Sheets1!A13', $body, $options );

,где в переменной $spreadsheetId указываем id таблицы.

5) Запустим скрипт из командной строки. Он предложит открыть ссылку которую выведет на экран. По переходу по ссылке будет показан стандарный диалог «Бал-бла- Разрешить?». Разрешаем. На экран выведется токен. Его нужно будет скопировать в консоль.

После чего снова запускаем скрипт, и в таблице в конец последних заполненных ячеек добавятся данные.

В чем опасность использовать прямую работу с БД если есть API

Жил был скрипт, который использовал вот таакой запрос к БД Zabbix:

select sendto from media where userid in (select userid from (select users_groups.userid from operations inner join opmessage_grp on opmessage_grp.operationid=operations.operationid inner join users_groups on opmessage_grp.usrgrpid=users_groups.usrgrpid where operations.actionid in (select actionid from conditions where conditiontype=2 and value=%s union all select actionid from conditions where conditiontype=0 and value in (SELECT groups.groupid FROM triggers INNER JOIN functions ON triggers.triggerid=functions.triggerid INNER JOIN items ON items.itemid=functions.itemid INNER JOIN hosts ON hosts.hostid=items.hostid INNER JOIN hosts_groups ON hosts_groups.hostid=hosts.hostid INNER JOIN groups ON groups.groupid=hosts_groups.groupid WHERE triggers.triggerid=%s) union all select actionid from conditions where conditiontype=1 and value in (SELECT hosts.hostid FROM triggers INNER JOIN functions ON triggers.triggerid=functions.triggerid INNER JOIN items ON items.itemid=functions.itemid INNER JOIN hosts ON hosts.hostid=items.hostid INNER JOIN hosts_groups ON hosts_groups.hostid=hosts.hostid INNER JOIN groups ON groups.groupid=hosts_groups.groupid WHERE triggers.triggerid=%s)) union all select opmessage_usr.userid from operations inner join opmessage_usr on opmessage_usr.operationid=operations.operationid where operations.actionid in (select actionid from conditions where conditiontype=2 and value in (select triggers.triggerid from triggers where triggers.triggerid = %s union all select triggers.templateid from triggers where triggers.triggerid = %s) union all select actionid from conditions where conditiontype=0 and value in (SELECT groups.groupid FROM triggers INNER JOIN functions ON triggers.triggerid=functions.triggerid INNER JOIN items ON items.itemid=functions.itemid INNER JOIN hosts ON hosts.hostid=items.hostid INNER JOIN hosts_groups ON hosts_groups.hostid=hosts.hostid INNER JOIN groups ON groups.groupid=hosts_groups.groupid WHERE triggers.triggerid=%s) union all select actionid from conditions where conditiontype=1 and value in (SELECT hosts.hostid FROM triggers INNER JOIN functions ON triggers.triggerid=functions.triggerid INNER JOIN items ON items.itemid=functions.itemid INNER JOIN hosts ON hosts.hostid=items.hostid INNER JOIN hosts_groups ON hosts_groups.hostid=hosts.hostid INNER JOIN groups ON groups.groupid=hosts_groups.groupid WHERE triggers.triggerid=%s))) as us group by userid union all select userid from users_groups where usrgrpid=18) and mediatypeid=5

Единственной функцией котого было дать список телефонов пользователей по id триггера. И работал бы этот скрипт еще долго, если бы не случилось обновление Zabbix с 3.4 до 4.4 Структура БД изменилась. Запрос работать перестал. Посмотрел я на него, посмотрел.. И понял, я наверное был не в себе когда его писал, и повторить такой подвиг больше не смогу. Решил переписать его использую API Zabbix. Вышло много понятнее 😉

echo "-получаем api-key\n";
$res=$zab->Auth($login, $password);

$triggerid=$options["t"];
$txt=$options["s"];
$users_id_for_sms=array();
echo "-действия по триггеру\n";
$res=$zab->Execute("action.get", ["triggerids"=>$triggerid,"output"=>'extend','selectOperations'=>'extend','selectRecoveryOperations'=>'extend','selectFilter'=>'extend']);
ParseRes($res);
echo "-получаем хост\n";
$hosts=$zab->Execute("host.get", ["triggerids"=>$triggerid]);
foreach ($hosts->result as $host) {
    $hostid=$host->hostid;
    $hostname=$host->name;
    echo "--действия по хосту $hostid $hostname\n";
    $res=$zab->Execute("action.get", ["hostids"=>$hostid,"output"=>'extend','selectOperations'=>'extend','selectRecoveryOperations'=>'extend','selectFilter'=>'extend']);
    ParseRes($res);
    $hostsg=$zab->Execute("hostgroup.get", ["hostids"=>$hostid]);
    foreach ($hostsg->result as $hostg) {
        $groupid=$hostg->groupid;
        echo "--- действия по группе хоста $groupid\n";   
        $res=$zab->Execute("action.get", ["groupids"=>$groupid,"output"=>'extend','selectOperations'=>'extend','selectRecoveryOperations'=>'extend','selectFilter'=>'extend']);
        ParseRes($res);

    }    
};
echo "- пользователи ZABBIX\n";   
var_dump($users_id_for_sms); 
$sms=array();
foreach ($users_id_for_sms as $userid) {    
    $res=$zab->Execute("user.get", ["userids"=>$userid,"output"=>'extend','status'=>0,"selectMedias"=>"extend"]);                     
    foreach ($res->result as $usersinfo) {        
        foreach ($usersinfo->medias as $md) {
            if ($md->mediatypeid==5){
              $sms[]=$md->sendto;  
            };
        };
        
    }
}
var_dump($sms);

function ParseRes($res){
global $zab,$users_id_for_sms;
    if (count($res->result)!=0){
        foreach ($res->result as $oper) {
            foreach ($oper->operations as $vl) {
                echo "---получаю пользователей группы\n";
                foreach ($vl->opmessage_grp as $usergroups) {
                  $usrgrpid= $usergroups->usrgrpid;
                  echo "----$usrgrpid\n";
                  $res=$zab->Execute("user.get", ["usrgrpids"=>$usrgrpid,"output"=>'extend','status'=>0]);                  
                  foreach ($res->result as $user) {
                   $users_id_for_sms[]=$user->userid;
                  };                                                      
//                  $res=$zab->Execute("user.get", ["usrgrpids"=>15,"output"=>'extend','status'=>0]);                  
//                  foreach ($res->result as $user) {
//                   $users_id_for_sms[]=$user->userid;
//                  };                                                                        
                };
                echo "---добавляю просто пользователей\n";                
                 //var_dump($vl->opmessage_usr);
                foreach ($vl->opmessage_usr as $userslist) {
                   $users_id_for_sms[]= $userslist->userid;
                };
                
            };            
        }
    };                             
};

Работа с API Zabbix из PHP

Поискал, поискал, ничего толкового не нашел. Пришлось написать самому. Выложил на GitHub. Описание актуального API Zabbix тут.

Пример использования:

include_once 'zabbix.php';

$url="https://my_zabbix.ru/api_jsonrpc1.php";
$login="weoriufeowiuf";
$password="owerierfoiewroi";

@include_once 'config.php';

// инициализация класса true/false - вывод в режиме debug
$zab=new Tzabbix(false);
$zab->SetCurlOpt(CURLOPT_URL,$url);
echo "-получаем api-key\n";
$res=$zab->Auth($login, $password);
if (isset($res->result)==true){
    if ($res->result!==false){        
        $res=$zab->Execute("host.get", ["output"=>["hostid","host"],"selectInterfaces"=>["interfaceid","ip"]]);
        var_dump($res);
    } else {
        var_dump($res);        
        die(-1);
    };    
} else {
  echo "--не понятная ошибка. попробуйте переключить в debug=true";  
};

Простейшая авторизация на PHP

Иногда проще бывает встроить «базовую» авторизацию в скрипт, чем «пилить» что-то специальное под авторизацию. К счастью протокол HTTP позволяет это сделать — а именно перед открытием страницы можно спросить у пользователя…ну например банальное логин-пароль. Например так:

if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="Enter login and passowrd"');
    header('HTTP/1.0 401 Unauthorized');
    echo 'Без авторизации нельзя!';
    exit;
}  else {

if (($_SERVER['PHP_AUTH_USER']=="pavel") and ($_SERVER['PHP_AUTH_PW']=="lkeslek")){

} else {
 die("Логин пароль не верен!");
};