PHP Classes

File: src/Generics/Socket/SecureSocket.php

Recommend this page to a friend!
  Classes of Maik Greubel   PHP Generics   src/Generics/Socket/SecureSocket.php   Download  
File: src/Generics/Socket/SecureSocket.php
Role: Class source
Content type: text/plain
Description: Class source
Class: PHP Generics
Framework for accessing streams, sockets and logs
Author: By
Last change: Update of src/Generics/Socket/SecureSocket.php
Date: 7 months ago
Size: 5,936 bytes
 

Contents

Class file image Download
<?php
/**
 * This file is part of the PHP Generics package.
 *
 * @package Generics
 */
namespace Generics\Socket;

use
Composer\CaBundle\CaBundle;
use
Generics\ResetException;
use
Generics\Streams\SocketStream;
use
Countable;
use
Exception;

/**
 * This abstract class provides basic secure socket functionality
 *
 * @author Maik Greubel <greubel@nkey.de>
 */
abstract class SecureSocket implements SocketStream
{

   
/**
     * The socket handle
     *
     * @var resource
     */
   
protected $handle;

   
/**
     * The socket endpoint
     *
     * @var Endpoint
     */
   
protected $endpoint;

   
/**
     * The stream context
     *
     * @var resource
     */
   
private $streamContext;

   
/**
     * Create a new socket
     *
     * @param Endpoint $endpoint
     * The endpoint for the socket
     */
   
public function __construct(Endpoint $endpoint)
    {
       
$this->endpoint = $endpoint;
       
$this->open();
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\InputStream::read()
     */
   
public function read($length = 1, $offset = null): string
   
{
        return
stream_get_contents($this->handle, $length, $offset === null ? - 1 : intval($offset));
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\Stream::isOpen()
     */
   
public function isOpen(): bool
   
{
        return
is_resource($this->handle) && ! feof($this->handle);
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\OutputStream::flush()
     */
   
public function flush()
    {
       
// flush not available on streams
   
}

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\Stream::ready()
     */
   
public function ready(): bool
   
{
        if (!
is_resource($this->handle)) {
            return
false;
        }
       
       
$read = array(
           
$this->handle
       
);
       
$write = null;
       
$except = null;
       
       
$num = @stream_select($read, $write, $except, 0);
       
        if (
$num === false) {
            throw new
SocketException("Could not determine the stream client status");
        }
       
        if (
$num < 1) {
            return
false;
        }
       
        if (!
in_array($this->handle, $read)) {
            return
false;
        }
       
        return
true;
    }

   
/**
     *
     * {@inheritdoc}
     * @see Countable::count()
     */
   
public function count()
    {
       
$meta = stream_get_meta_data($this->handle);
       
        foreach (
$meta as $data) {
            if (
strstr($data, 'Content-Length:')) {
                return
intval(trim(substr($data, 15)));
            }
        }
        throw new
SocketException("Cannot count elements of stream client");
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Resettable::reset()
     */
   
public function reset()
    {
        try {
           
$this->close();
           
$this->open();
        } catch (
Exception $ex) {
            throw new
ResetException($ex->getMessage(), array(), $ex->getCode(), $ex);
        }
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\Stream::close()
     */
   
public function close()
    {
        if (
is_resource($this->handle)) {
           
fclose($this->handle);
           
$this->handle = null;
        }
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\OutputStream::write()
     */
   
public function write($buffer)
    {
        if (!
$this->isWriteable()) {
            throw new
SocketException("Stream is not ready for writing");
        }
       
$len = strlen($buffer);
       
$written = 0;
        do {
           
$bytes = fwrite($this->handle, $buffer);
            if (
$bytes === false) {
                throw new
SocketException("Could not write {len} bytes to stream (at least {written} written)", array(
                   
'len' => $len,
                   
'written' => $written
               
));
            }
           
$written += $bytes;
        } while (
$written != $len);
    }

   
/**
     *
     * {@inheritdoc}
     * @see \Generics\Streams\OutputStream::isWriteable()
     */
   
public function isWriteable(): bool
   
{
        if (!
is_resource($this->handle)) {
            return
false;
        }
       
       
$read = null;
       
$write = array(
           
$this->handle
       
);
       
$except = null;
       
       
$num = @stream_select($read, $write, $except, 0, 0);
       
        if (
$num === false) {
            throw new
SocketException("Could not determine the stream client status");
        }
       
        if (
$num < 1) {
            return
false;
        }
       
        if (!
in_array($this->handle, $write)) {
            return
false;
        }
       
        return
true;
    }

    private function
open()
    {
       
$this->prepareStreamContext();
       
       
$this->handle = stream_socket_client(
           
sprintf('ssl://%s:%d', $this->endpoint->getAddress(), $this->endpoint->getPort()), //
           
$error,
           
$errorString,
           
2,
           
STREAM_CLIENT_CONNECT,
           
$this->streamContext
       
);
       
        if (
$error > 0) {
            throw new
SocketException($errorString, array(), $error);
        }
    }

    private function
prepareStreamContext()
    {
       
$opts = array(
           
'http' => array(
               
'method' => "GET"
           
)
        );
       
       
$caPath = CaBundle::getSystemCaRootBundlePath();
       
        if (
is_dir($caPath)) {
           
$opts['ssl']['capath'] = $caPath;
        } else {
           
$opts['ssl']['cafile'] = $caPath;
        }
       
       
$this->streamContext = stream_context_create($opts);
    }

   
/**
     * Retrieve end point object
     *
     * @return Endpoint
     */
   
public function getEndPoint(): Endpoint
   
{
        return
$this->endpoint;
    }
}