├── README.md ├── composer.json └── src ├── Vote.php └── Server.php /README.md: -------------------------------------------------------------------------------- 1 | # votifier2-php 2 | 3 | Votifier protocol v2 client for PHP. 4 | 5 | ## Example 6 | 7 | ```php 8 | $vote = new \Imaginarycode\Votifier2\Vote("tuxed", "127.0.0.1", "Test", NULL); 9 | $service = new \Imaginarycode\Votifier2\Server("127.0.0.1", 8192, "TOKEN"); 10 | $service->sendVote($vote); 11 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuvotifier/votifier2-php", 3 | "description": "A Votifier protocol 2 implementation for PHP", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "Tux", 8 | "email": "write@imaginarycode.com" 9 | } 10 | ], 11 | "require": {}, 12 | "autoload": { 13 | "psr-4": { 14 | "Imaginarycode\\Votifier2\\": "src/" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Vote.php: -------------------------------------------------------------------------------- 1 | serviceName = $serviceName; 19 | $this->username = $username; 20 | $this->address = $address; 21 | // We lose some precision if we have to make this up, but that's okay. 22 | $this->timestamp = $timestamp ?: (int) (time() * 1000); 23 | } 24 | } -------------------------------------------------------------------------------- /src/Server.php: -------------------------------------------------------------------------------- 1 | host = $host; 20 | $this->port = $port; 21 | $this->token = $token; 22 | } 23 | 24 | /** 25 | * Sends a vote. 26 | * @param Vote $vote 27 | * @throws \ErrorException 28 | */ 29 | public function sendVote(Vote $vote) 30 | { 31 | if (!$vote) 32 | { 33 | throw new \InvalidArgumentException('vote not provided'); 34 | } 35 | 36 | $stream = stream_socket_client('tcp://' . $this->host . ':' . $this->port, $errno, $errstr, 3); 37 | if (!$stream) 38 | { 39 | throw new \Exception('Could not connect: ' . $errstr); 40 | } 41 | 42 | try { 43 | stream_set_timeout($stream, 3); 44 | $header = fread($stream, 64); 45 | if ($header === FALSE) { 46 | throw new \Exception("Couldn't read header from remote host"); 47 | } 48 | $header_parts = explode(' ', $header); 49 | 50 | if (count($header_parts) != 3) { 51 | throw new \Exception('Not a Votifier v2 server'); 52 | } 53 | 54 | $challenge = substr($header_parts[2], 0, -1); 55 | 56 | $payload_json = json_encode(array( 57 | "username" => $vote->username, 58 | "serviceName" => $vote->serviceName, 59 | "timestamp" => $vote->timestamp, 60 | "address" => $vote->address, 61 | "challenge" => $challenge 62 | )); 63 | $signature = base64_encode(hash_hmac('sha256', $payload_json, $this->token, true)); 64 | $message_json = json_encode(array("signature" => $signature, "payload" => $payload_json)); 65 | 66 | $payload = pack('nn', 0x733a, strlen($message_json)) . $message_json; 67 | if (fwrite($stream, $payload) === FALSE) { 68 | throw new \Exception("Couldn't write to remote host"); 69 | } 70 | 71 | $response = fread($stream, 256); 72 | 73 | if (!$response) { 74 | throw new \Exception('Unable to read server response'); 75 | } 76 | 77 | $result = json_decode($response); 78 | if ($result->status !== "ok") { 79 | throw new \Exception('Votifier server error: ' . $result->cause . ': ' . $result->error); 80 | } 81 | } finally { 82 | fclose($stream); 83 | } 84 | } 85 | } --------------------------------------------------------------------------------