├── .gitignore ├── README ├── src └── Net │ └── Zabbix │ ├── Exception │ ├── SenderRuntimeException.php │ ├── SenderNetworkException.php │ └── SenderProtocolException.php │ ├── Agent │ └── Config.php │ └── Sender.php ├── composer.json ├── tests ├── Net │ └── Zabbix │ │ ├── Agent │ │ └── ConfigTest.php │ │ └── SenderTest.php └── bootstrap.php └── examples └── sample.php /.gitignore: -------------------------------------------------------------------------------- 1 | run_test 2 | 3 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | pure PHP Zabbix Sender Library 2 | 3 | Requirement 4 | PHP5.3 5 | PHPUnit 6 | 7 | -------------------------------------------------------------------------------- /src/Net/Zabbix/Exception/SenderRuntimeException.php: -------------------------------------------------------------------------------- 1 | =5.3.2" 13 | }, 14 | "autoload": { 15 | "psr-0": {"Net\\Zabbix": "src/"} 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tests/Net/Zabbix/Agent/ConfigTest.php: -------------------------------------------------------------------------------- 1 | config = new \Net\Zabbix\Agent\Config('/etc/zabbix/zabbix_agentd.conf'); 8 | } 9 | 10 | public function test_set_getConfigFilename() 11 | { 12 | $this->assertEquals('/etc/zabbix/zabbix_agentd.conf',$this->config->getCurrentConfigFilename()); 13 | } 14 | 15 | public function test_getConfigArrayHasKey_Server() 16 | { 17 | $this->assertArrayHasKey('Server',$this->config->getConfigArray()); 18 | } 19 | 20 | public function test_getConfigArrayHasKey_ServerPort() 21 | { 22 | $this->assertArrayHasKey('ServerPort',$this->config->getConfigArray()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | DIRECTORY_SEPARATOR, 11 | '\\' => DIRECTORY_SEPARATOR, 12 | '.' => '', 13 | ); 14 | $classPath = str_replace(array_keys($replaces),array_values($replaces),$className); 15 | $fileName = $src . DIRECTORY_SEPARATOR . $classPath . '.php'; 16 | 17 | if(is_file($fileName)){ 18 | require_once($fileName); 19 | } 20 | } 21 | 22 | spl_autoload_register('my_autoload'); 23 | 24 | -------------------------------------------------------------------------------- /src/Net/Zabbix/Agent/Config.php: -------------------------------------------------------------------------------- 1 | _config_filename = isset($filename) && is_readable($filename) 14 | ? $filename : '/etc/zabbix/zabbix_agentd.conf'; 15 | $this->_config_array = $this->_load($this->_config_filename); 16 | } 17 | 18 | function getConfigArray(){ 19 | return $this->_config_array; 20 | } 21 | 22 | function getServer(){ 23 | $return_value = null; 24 | if( array_key_exists('Server',$this->_config_array) ) 25 | { 26 | $return_value = $this->_config_array{'Server'}; 27 | } 28 | return $return_value; 29 | } 30 | 31 | function getServerPort(){ 32 | $return_value = null; 33 | if( array_key_exists('ServerPort',$this->_config_array) 34 | and is_numeric($this->_config_array{'ServerPort'}) ) 35 | { 36 | $return_value = intval($this->_config_array{'ServerPort'}); 37 | } 38 | return $return_value; 39 | } 40 | 41 | function getCurrentConfigFilename() 42 | { 43 | return $this->_config_filename; 44 | } 45 | 46 | function _load($filename=null){ 47 | $config_array = array(); 48 | if( isset($filename) and is_readable($filename) ){ 49 | $config_lines = file($filename); 50 | $config_lines = preg_grep("/^\s*[A-Za-z].+\=.+/",$config_lines); 51 | foreach($config_lines as $line_num => $line){ 52 | list($key,$value) = explode("=",$line,2); 53 | $key = trim($key); 54 | $value = trim($value); 55 | $config_array{$key} = $value; 56 | } 57 | } 58 | return $config_array; 59 | } 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /tests/Net/Zabbix/SenderTest.php: -------------------------------------------------------------------------------- 1 | sender = new Net\Zabbix\Sender('localhost',10051); 8 | $agentConfig = new Net\Zabbix\Agent\Config(); 9 | $this->sender->importAgentConfig($agentConfig); 10 | } 11 | 12 | public function test_set_getTimeout() 13 | { 14 | $timeout = 99; 15 | $this->sender->setTimeout($timeout); 16 | $this->assertEquals($timeout,$this->sender->getTimeout()); 17 | } 18 | 19 | function _addData(\Net\Zabbix\Sender $sender){ 20 | $sender->addData("hostname1","key1","value1"); 21 | $sender->addData("hostname2","key2","value2"); 22 | $sender->addData("hostname3","key3","value3",1234567890); 23 | } 24 | 25 | public function test_addData() 26 | { 27 | $this->_addData($this->sender); 28 | $dataArray = $this->sender->getDataArray(); 29 | $this->assertCount(3,$dataArray); 30 | } 31 | 32 | public function test_unsetData() 33 | { 34 | $this->_addData($this->sender); 35 | $this->sender->initData(); 36 | $dataArray = $this->sender->getDataArray(); 37 | $this->assertCount(0,$dataArray); 38 | } 39 | 40 | /** 41 | * @expectedException Net\Zabbix\Exception\SenderNetworkException 42 | */ 43 | public function test_send_fail_invalid_hostname() 44 | { 45 | $this->sender->setServerName('invalid-hostname'); 46 | $result = $this->sender->send(); 47 | $this->assertFalse($result); 48 | } 49 | 50 | /** 51 | * @expectedException Net\Zabbix\Exception\SenderNetworkException 52 | */ 53 | public function test_send_fail_invalid_port() 54 | { 55 | $this->sender->setServerPort(11111); 56 | $result = $this->sender->send(); 57 | $this->assertFalse($result); 58 | } 59 | 60 | public function test_send() 61 | { 62 | $this->_addData($this->sender); 63 | $result = $this->sender->send(); 64 | $this->assertTrue($result); 65 | $this->assertEquals(3,$this->sender->getLastFailed()); 66 | $this->assertEquals(0,$this->sender->getLastProcessed()); 67 | $this->assertEquals(3,$this->sender->getLastTotal()); 68 | $this->assertGreaterThanOrEqual(0.000000001,$this->sender->getLastSpent()); 69 | $this->assertArrayHasKey('info',$this->sender->getLastResponseArray()); 70 | $this->assertArrayHasKey('response',$this->sender->getLastResponseArray()); 71 | $this->assertRegExp('/Processed \d+ Failed \d+ Total \d+ Seconds spent \d+\.\d+/', 72 | $this->sender->getLastResponseInfo()); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /examples/sample.php: -------------------------------------------------------------------------------- 1 | importAgentConfig($agentConfig); 12 | 13 | ## fail request 14 | $sender->addData($undefined_hostname,'custom.string1','string0'); 15 | 16 | ## defined host 17 | # string 18 | $sender->addData($defined_hostname,'custom.string1','string1'); 19 | $sender->addData($defined_hostname,'custom.string1','string2'); 20 | # int 21 | $sender->addData($defined_hostname,'custom.int1','99','1234567890'); #with timestamp 22 | $sender->addData($defined_hostname,'custom.int1',intval('2')); 23 | $sender->addData($defined_hostname,'custom.int1','1'); 24 | # float 25 | $sender->addData($defined_hostname,'custom.float1',strval('3.14')); # store 3.14 26 | $sender->addData($defined_hostname,'custom.float1',floatval('3.24')); # store 3 27 | $sender->addData($defined_hostname,'custom.float1','6.14'); 28 | # text 29 | $sender->addData($defined_hostname,'custom.text1','text1'); 30 | $sender->addData($defined_hostname,'custom.text1','text2'); 31 | # log 32 | $sender->addData($defined_hostname,'custom.log1','log1'); 33 | $sender->addData($defined_hostname,'custom.log1','log2'); 34 | 35 | $result = $sender->send(); 36 | 37 | if($result){ 38 | $info = $sender->getLastResponseInfo(); 39 | $data = $sender->getLastResponseArray(); 40 | echo "request result: success\n"; 41 | echo "response info: $info\n"; 42 | echo "response data:\n"; 43 | var_dump($data); 44 | 45 | $processed = $sender->getLastProcessed(); 46 | $failed = $sender->getLastFailed(); 47 | $total = $sender->getLastTotal(); 48 | $spent = $sender->getLastSpent(); 49 | echo "parsedInfo: processed = $processed\n"; 50 | echo "parsedInfo: failed = $failed\n"; 51 | echo "parsedInfo: total = $total\n"; 52 | echo "parsedInfo: spent = $spent\n"; 53 | 54 | }else{ 55 | echo "request result: failed\n"; 56 | } 57 | 58 | 59 | /* 60 | method chain pattern 61 | */ 62 | $sender = new \Net\Zabbix\Sender(); 63 | $result = $sender 64 | ->setServerName('localhost') 65 | ->setServerPort(10051) 66 | ->setTimeout(10) 67 | ->addData($undefined_hostname,'custom.string1','string0') 68 | ->addData($defined_hostname,'custom.string1','string1') 69 | ->addData($defined_hostname,'custom.string1','string1') 70 | ->addData($defined_hostname,'custom.string1','string1') 71 | ->send(); 72 | if($result){ 73 | $info = $sender->getLastResponseInfo(); 74 | $data = $sender->getLastResponseArray(); 75 | echo "request result: success\n"; 76 | echo "response info: $info\n"; 77 | echo "response data:\n"; 78 | var_dump($data); 79 | 80 | $processed = $sender->getLastProcessed(); 81 | $failed = $sender->getLastFailed(); 82 | $total = $sender->getLastTotal(); 83 | $spent = $sender->getLastSpent(); 84 | echo "parsedInfo: processed = $processed\n"; 85 | echo "parsedInfo: failed = $failed\n"; 86 | echo "parsedInfo: total = $total\n"; 87 | echo "parsedInfo: spent = $spent\n"; 88 | 89 | }else{ 90 | echo "request result: failed\n"; 91 | } 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/Net/Zabbix/Sender.php: -------------------------------------------------------------------------------- 1 | setServerName($servername); 38 | $this->setServerPort($serverport); 39 | $this->initData(); 40 | } 41 | 42 | function initData() 43 | { 44 | $this->_data = array( 45 | "request" => "sender data", 46 | "data" => array() 47 | ); 48 | } 49 | 50 | function importAgentConfig(Agent\Config $agentConfig) 51 | { 52 | $this->setServerName($agentConfig->getServer()); 53 | $this->setServerPort($agentConfig->getServerPort()); 54 | return $this; 55 | } 56 | 57 | function setServerName($servername){ 58 | $this->_servername = $servername; 59 | return $this; 60 | } 61 | 62 | function setServerPort($serverport){ 63 | if (is_int($serverport)) { 64 | $this->_serverport = $serverport; 65 | } 66 | return $this; 67 | } 68 | 69 | function setTimeout($timeout=0){ 70 | if( (is_int($timeout) or is_numeric($timeout) ) and intval($timeout) > 0){ 71 | $this->_timeout = $timeout; 72 | } 73 | return $this; 74 | } 75 | 76 | function getTimeout(){ 77 | return $this->_timeout; 78 | } 79 | 80 | function setProtocolHeaderString($headerString){ 81 | $this->_protocolHeaderString = $headerString; 82 | return $this; 83 | } 84 | 85 | function setProtocolVersion($version){ 86 | if (is_int($version) and $version > 0) { 87 | $this->_protocolVersion = $version; 88 | } 89 | return $this; 90 | } 91 | 92 | function addData($hostname=null,$key=null,$value=null,$clock=null) 93 | { 94 | $input = array("host"=>$hostname,"value"=>$value,"key"=>$key); 95 | if( isset($clock) ){ 96 | $input{"clock"} = $clock; 97 | } 98 | array_push($this->_data{"data"},$input); 99 | return $this; 100 | } 101 | 102 | function getDataArray() 103 | { 104 | return $this->_data{"data"}; 105 | } 106 | 107 | private function _buildSendData(){ 108 | $json_data = json_encode( array_map( 109 | function($t){ return is_string($t) ? utf8_encode($t) : $t; }, 110 | $this->_data 111 | ) 112 | ); 113 | $json_length = strlen($json_data); 114 | $data_header = pack("aaaaCCCCCCCCC", 115 | substr($this->_protocolHeaderString,0,1), 116 | substr($this->_protocolHeaderString,1,1), 117 | substr($this->_protocolHeaderString,2,1), 118 | substr($this->_protocolHeaderString,3,1), 119 | intval($this->_protocolVersion), 120 | ($json_length & 0xFF), 121 | ($json_length & 0x00FF)>>8, 122 | ($json_length & 0x0000FF)>>16, 123 | ($json_length & 0x000000FF)>>24, 124 | 0x00, 125 | 0x00, 126 | 0x00, 127 | 0x00 128 | ); 129 | return ($data_header . $json_data); 130 | } 131 | 132 | protected function _parseResponseInfo($info=null){ 133 | # info: "Processed 1 Failed 1 Total 2 Seconds spent 0.000035" 134 | $parsedInfo = null; 135 | if(isset($info)){ 136 | list(,$processed,,$failed,,$total,,,$spent) = explode(" ",$info); 137 | $parsedInfo = array( 138 | "processed" => intval($processed), 139 | "failed" => intval($failed), 140 | "total" => intval($total), 141 | "spent" => $spent, 142 | ); 143 | } 144 | return $parsedInfo; 145 | } 146 | 147 | function getLastResponseInfo(){ 148 | return $this->_lastResponseInfo; 149 | } 150 | 151 | function getLastResponseArray(){ 152 | return $this->_lastResponseArray; 153 | } 154 | 155 | function getLastProcessed(){ 156 | return $this->_lastProcessed; 157 | } 158 | 159 | function getLastFailed(){ 160 | return $this->_lastFailed; 161 | } 162 | 163 | function getLastSpent(){ 164 | return $this->_lastSpent; 165 | } 166 | 167 | function getLastTotal(){ 168 | return $this->_lastTotal; 169 | } 170 | 171 | private function _clearLastResponseData(){ 172 | $this->_lastResponseInfo = null; 173 | $this->_lastResponseArray = null; 174 | $this->_lastProcessed = null; 175 | $this->_lastFailed = null; 176 | $this->_lastSpent = null; 177 | $this->_lastTotal = null; 178 | } 179 | 180 | private function _close(){ 181 | if($this->_socket){ 182 | fclose($this->_socket); 183 | } 184 | } 185 | 186 | /** 187 | * connect to Zabbix Server 188 | * @throws Net\Zabbix\Exception\SenderNetworkException 189 | * 190 | */ 191 | private function _connect(){ 192 | $this->_socket = @fsockopen( $this->_servername, 193 | intval($this->_serverport), 194 | $errno, 195 | $errmsg, 196 | $this->_timeout); 197 | if(! $this->_socket){ 198 | throw new SenderNetworkException(sprintf('%s,%s',$errno,$errmsg)); 199 | } 200 | } 201 | 202 | /** 203 | * write data to socket 204 | * @throws Net\Zabbix\Exception\SenderNetworkException 205 | * 206 | */ 207 | private function _write($socket,$data){ 208 | if(! $socket){ 209 | throw new SenderNetworkException('socket was not writable,connect failed.'); 210 | } 211 | $totalWritten = 0; 212 | $length = strlen($data); 213 | while( $totalWritten < $length ){ 214 | $writeSize = @fwrite($socket,$data); 215 | if($writeSize === false){ 216 | return false; 217 | }else{ 218 | $totalWritten += $writeSize; 219 | $data = substr($data,$writeSize); 220 | } 221 | } 222 | return $totalWritten; 223 | } 224 | 225 | /** 226 | * read data from socket 227 | * @throws Net\Zabbix\Exception\SenderNetworkException 228 | * 229 | */ 230 | private function _read($socket){ 231 | if(! $socket){ 232 | throw new SenderNetworkException('socket was not readable,connect failed.'); 233 | } 234 | $recvData = ""; 235 | while(!feof($socket)){ 236 | $buffer = fread($socket,8192); 237 | if($buffer === false){ 238 | return false; 239 | } 240 | $recvData .= $buffer; 241 | } 242 | return $recvData; 243 | } 244 | 245 | 246 | /** 247 | * main 248 | * @throws Net\Zabbix\Exception\SenderNetworkException 249 | * @throws Net\Zabbix\Exception\SenderProtocolException 250 | * 251 | */ 252 | function send(){ 253 | $sendData = $this->_buildSendData(); 254 | $datasize = strlen($sendData); 255 | 256 | $this->_connect(); 257 | 258 | /* send data to zabbix server */ 259 | $sentsize = $this->_write($this->_socket,$sendData); 260 | if($sentsize === false or $sentsize != $datasize){ 261 | throw new SenderNetworkException('cannot receive response'); 262 | } 263 | 264 | /* receive data from zabbix server */ 265 | $recvData = $this->_read($this->_socket); 266 | if($recvData === false){ 267 | throw new SenderNetworkException('cannot receive response'); 268 | } 269 | 270 | $this->_close(); 271 | 272 | $recvProtocolHeader = substr($recvData,0,4); 273 | if( $recvProtocolHeader == "ZBXD"){ 274 | $responseData = substr($recvData,13); 275 | $responseArray = json_decode($responseData,true); 276 | if(is_null($responseArray)){ 277 | throw new SenderProtocolException('invalid json data in receive data'); 278 | } 279 | $this->_lastResponseArray = $responseArray; 280 | $this->_lastResponseInfo = $responseArray{'info'}; 281 | $parsedInfo = $this->_parseResponseInfo($this->_lastResponseInfo); 282 | $this->_lastProcessed = $parsedInfo{'processed'}; 283 | $this->_lastFailed = $parsedInfo{'failed'}; 284 | $this->_lastSpent = $parsedInfo{'spent'}; 285 | $this->_lastTotal = $parsedInfo{'total'}; 286 | if($responseArray{'response'} == "success"){ 287 | $this->initData(); 288 | return true; 289 | }else{ 290 | $this->_clearLastResponseData(); 291 | return false; 292 | } 293 | }else{ 294 | $this->_clearLastResponseData(); 295 | throw new SenderProtocolException('invalid protocol header in receive data'); 296 | } 297 | } 298 | } 299 | 300 | 301 | --------------------------------------------------------------------------------