Zabbix APIをPHPから呼び出す。

# 始めに
Zabbix（OSSの監視ツール）を導入し、定時で障害発生状況をメールでレポートするスクリプトを作成する必要があった。

Zabbixには定時で処理を流すような仕組みがないため、
障害の発生状況をZabbixサーバからZabbix APIで取得し、整形、メール送信を行うこととした。

そこで、PHPとPHP curlの例外処理を勉強することを目的とし
自前でZabbix APIを呼び出すため、APIクライアントを実装してみる。

# 環境

```shell-session
# cat /etc/redhat-release
CentOS Linux release 7.4.1708 (Core)

# rpm -qa | grep zabbix-server
zabbix-server-mysql-3.0.13-2.el7.x86_64

# php -v
PHP 5.4.16 (cli) (built: Nov 15 2017 16:33:54)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
```

# 方針
Zabbix API Clientクラスを作成し、以下の処理を行うメソッドを実装する。
0. コンストラクタ
1. ログイン
2. API 呼出
3. ログアウト

※レポートプログラムからは上記のクラスをインスタンス化して利用する。

# 実装
ログイン処理にAPIを呼び出す必要があるため 0 → 2 → 1 →3 の順番で記載する。

## インスタンス変数とコンストラクタ
```php
private $host =null;
private $id = null;
private $token = null;
private $api_prot = null;
private $api_path = null;

public function __construct($host, $api_prot = 'http', $api_path = '/zabbix/api_jsonrpc.php') {
    $this->host = (string)$host;
    $this->id = date('YmdHis');    // idとして日付日時を使用
    $this->api_prot = $api_prot;
    $this->api_path = $api_path;
}
```

## API 呼出
例外処理は参考情報参照

```php
// 引数
//   $method : ZabbixAPI名称
//   $params : ZabbixAPIのパラメータ
public function executeRequest($method, $params) {
//  json-rpc 2.0 に対応するようリクエストデータを生成
    $request = array(
        'jsonrpc'   => '2.0',
        'method'    => $method,
        'params'    => $params,
        'id'        => $this->id,
        'auth'      => $this->token
    );

//  リクエストデータをJSONに変換する。
    $request_json = json_encode($request);

//  URL生成
    $url = $this->api_prot . '://' . $this->host . $this->api_path;

//  curl初期化
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER => array('Content-Type: application/json-rpc'),  // リクエストヘッダ追加
        CURLOPT_FAILONERROR => true,               // HTTP で 400 以上のコードが返ってきた際に処理失敗と判断
        CURLOPT_RETURNTRANSFER => true,            // curl_exec() の返り値を文字列で返す
        CURLOPT_POST => true,                      // リクエストメソッドにPOSTを指定
        CURLOPT_POSTFIELDS => $request_json        // POSTするデータを設定
     ]);

//  curl実行
    $response_json = curl_exec($ch);

//  エラー情報取得
    $errno = curl_errno($ch);
    $error = curl_error($ch);

//  curlクローズ
    curl_close($ch);

    $response = json_decode($response_json , true);

    if (CURLE_OK !== $errno or empty($response)) {
//      HTTPリクエストに失敗した場合
        throw new HttpConnectionException($error, $errno);
    } elseif ( ! empty($response['error']) ) {
//      Zabbix サーバでエラーが発生した場合
        throw new ZabbixApiExeption($response['error']['data'], $response['error']['code']);
    }

    return $response;
}
```

## ログイン
```php
public function login($user, $pass) {
    $params = array(
        'user'      => $user,
        'password'  => $pass
    );
    $response = $this->executeRequest('user.login', $params);

//  取得したトークンをインスタンス変数に設定
//  ※失敗した場合、HttpConnectionException 、もしくは、ZabbixApiExeption がスローされる。
    $this->token = $response['result'];
}
```

## ログアウト

```php
public function logout() {
    $response = $this->executeRequest('user.logout', []);
    return $response['result'];
}
```

---
# 参考情報
## Zabbix 3.0 API Reference
- [Zabbix Documentation 3.0 - API](https://www.zabbix.com/documentation/3.0/manual/api)



## 呼出例
```php:main
$api = new ZabbixApi($zbx_host);
try {
    $api->login($zbx_user, $zbx_pass);
    $trigers = getTrigger($api);

} catch(ZabbixLibraryException $e) {
    echo "ERROR: " . $e->getMessage() . "\n";
    exit;
}
```

```php:getTrigger
public function getTrigger($api) {
    $method = 'trigger.get';
    $params = array(
        'templated'         => false,
        'monitored'         => true,
        'active '           => true,
        'maintenance'       => false,
        'skipDependent'     => true,
        'only_true'         => true,
        'output'            => ["description"],
        'expandData'        => 1,
        'monitored'         => 1,
        'min_severity'      => $this->mini_severity,
        'expandDescription' => true,
        'sortfield'         => 'hostname',
        'filter'            => array(
                'status'    => 0,
                'value'     => 1
        )
    );
    $response = $api->executeRequest($method, $params);
    return $response['result'];
}
```

## 例外クラス 
例外クラス用のインターフェイスクラスを作成し、自前で実装した例外クラスに継承させ、
APIクライアントで発生した例外のみをcatchできるように実装した。

```php
interface ZabbixLibraryException { }

class HttpConnectionException extends \RuntimeException implements ZabbixLibraryException { }

class ZabbixApiExeption extends \RuntimeException implements ZabbixLibraryException { }
```