Download project

This commit is contained in:
Roman Pyrih
2024-11-20 09:09:44 +01:00
parent 547a138d6a
commit 5ff041757f
40737 changed files with 7766183 additions and 0 deletions

View File

@@ -0,0 +1,170 @@
<?php
namespace ps_metrics_module_v4_0_5;
require __DIR__ . '/Consumer.php';
require __DIR__ . '/QueueConsumer.php';
require __DIR__ . '/Consumer/File.php';
require __DIR__ . '/Consumer/ForkCurl.php';
require __DIR__ . '/Consumer/Socket.php';
class Segment_Client
{
/**
* VERSION
*/
const VERSION = "1.0.0";
private $consumer;
/**
* Create a new analytics object with your app's secret
* key
*
* @param string $secret
* @param array $options array of consumer options [optional]
* @param string Consumer constructor to use, socket by default.
*/
public function __construct($secret, $options = array())
{
$consumers = array("socket" => "ps_metrics_module_v4_0_5\Segment_Consumer_Socket", "file" => "Segment_Consumer_File", "fork_curl" => "Segment_Consumer_ForkCurl");
# Use our socket consumer by default
$consumer_type = isset($options["consumer"]) ? $options["consumer"] : "socket";
$Consumer = $consumers[$consumer_type];
$this->consumer = new $Consumer($secret, $options);
}
public function __destruct()
{
$this->consumer->__destruct();
}
/**
* Tracks a user action
*
* @param array $message
* @return [boolean] whether the track call succeeded
*/
public function track(array $message)
{
$message = $this->message($message);
$message["type"] = "track";
return $this->consumer->track($message);
}
/**
* Tags traits about the user.
*
* @param [array] $message
* @return [boolean] whether the track call succeeded
*/
public function identify(array $message)
{
$message = $this->message($message);
$message["type"] = "identify";
return $this->consumer->identify($message);
}
/**
* Tags traits about the group.
*
* @param [array] $message
* @return [boolean] whether the group call succeeded
*/
public function group(array $message)
{
$message = $this->message($message);
$message["type"] = "group";
return $this->consumer->group($message);
}
/**
* Tracks a page view.
*
* @param [array] $message
* @return [boolean] whether the page call succeeded
*/
public function page(array $message)
{
$message = $this->message($message);
$message["type"] = "page";
return $this->consumer->page($message);
}
/**
* Tracks a screen view.
*
* @param [array] $message
* @return [boolean] whether the screen call succeeded
*/
public function screen(array $message)
{
$message = $this->message($message);
$message["type"] = "screen";
return $this->consumer->screen($message);
}
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public function alias(array $message)
{
$message = $this->message($message);
$message["type"] = "alias";
return $this->consumer->alias($message);
}
/**
* Flush any async consumers
*/
public function flush()
{
if (!\method_exists($this->consumer, 'flush')) {
return;
}
$this->consumer->flush();
}
/**
* Formats a timestamp by making sure it is set, and then converting it to
* iso8601 format.
* @param time $timestamp - time in seconds (time())
*/
private function formatTime($timestamp)
{
if ($timestamp == null) {
$timestamp = \time();
}
# Format for iso8601
return \date("c", $timestamp);
}
/**
* Add common fields to the gvien `message`
*
* @param array $msg
* @return array
*/
private function message($msg)
{
if (!isset($msg["context"])) {
$msg["context"] = array();
}
if (!isset($msg["timestamp"])) {
$msg["timestamp"] = null;
}
$msg["context"] = \array_merge($msg["context"], $this->getContext());
$msg["timestamp"] = $this->formatTime($msg["timestamp"]);
$msg["messageId"] = self::messageId();
return $msg;
}
/**
* Generate a random messageId.
*
* https://gist.github.com/dahnielson/508447#file-uuid-php-L74
*
* @return string
*/
private static function messageId()
{
return \sprintf("%04x%04x-%04x-%04x-%04x-%04x%04x%04x", \mt_rand(0, 0xffff), \mt_rand(0, 0xffff), \mt_rand(0, 0xffff), \mt_rand(0, 0xfff) | 0x4000, \mt_rand(0, 0x3fff) | 0x8000, \mt_rand(0, 0xffff), \mt_rand(0, 0xffff), \mt_rand(0, 0xffff));
}
/**
* Add the segment.io context to the request
* @return array additional context
*/
private function getContext()
{
return array("library" => array("name" => "analytics-php", "version" => self::VERSION));
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace ps_metrics_module_v4_0_5;
abstract class Segment_Consumer
{
protected $type = "Consumer";
protected $options;
protected $secret;
/**
* Store our secret and options as part of this consumer
* @param string $secret
* @param array $options
*/
public function __construct($secret, $options = array())
{
$this->secret = $secret;
$this->options = $options;
}
/**
* Tracks a user action
*
* @param array $message
* @return boolean whether the track call succeeded
*/
public abstract function track(array $message);
/**
* Tags traits about the user.
*
* @param array $message
* @return boolean whether the identify call succeeded
*/
public abstract function identify(array $message);
/**
* Tags traits about the group.
*
* @param array $message
* @return boolean whether the group call succeeded
*/
public abstract function group(array $message);
/**
* Tracks a page view.
*
* @param array $message
* @return boolean whether the page call succeeded
*/
public abstract function page(array $message);
/**
* Tracks a screen view.
*
* @param array $message
* @return boolean whether the group call succeeded
*/
public abstract function screen(array $message);
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public abstract function alias(array $message);
/**
* Check whether debug mode is enabled
* @return boolean
*/
protected function debug()
{
return isset($this->options["debug"]) ? $this->options["debug"] : \false;
}
/**
* Check whether we should connect to the API using SSL. This is enabled by
* default with connections which make batching requests. For connections
* which can save on round-trip times, we disable it.
* @return boolean
*/
protected function ssl()
{
return isset($this->options["ssl"]) ? $this->options["ssl"] : \false;
}
/**
* On an error, try and call the error handler, if debugging output to
* error_log as well.
* @param string $code
* @param string $msg
*/
protected function handleError($code, $msg)
{
if (isset($this->options['error_handler'])) {
$handler = $this->options['error_handler'];
$handler($code, $msg);
}
if ($this->debug()) {
\error_log("[Analytics][" . $this->type . "] " . $msg);
}
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace ps_metrics_module_v4_0_5;
class Segment_Consumer_File extends Segment_Consumer
{
private $file_handle;
protected $type = "File";
/**
* The file consumer writes track and identify calls to a file.
* @param string $secret
* @param array $options
* string "filename" - where to log the analytics calls
*/
public function __construct($secret, $options = array())
{
if (!isset($options["filename"])) {
$options["filename"] = \sys_get_temp_dir() . \DIRECTORY_SEPARATOR . "analytics.log";
}
parent::__construct($secret, $options);
try {
$this->file_handle = \fopen($options["filename"], "a");
\chmod($options["filename"], 0777);
} catch (\Exception $e) {
$this->handleError($e->getCode(), $e->getMessage());
}
}
public function __destruct()
{
if ($this->file_handle && \get_resource_type($this->file_handle) != "Unknown") {
\fclose($this->file_handle);
}
}
/**
* Tracks a user action
*
* @param array $message
* @return [boolean] whether the track call succeeded
*/
public function track(array $message)
{
return $this->write($message);
}
/**
* Tags traits about the user.
*
* @param array $message
* @return [boolean] whether the identify call succeeded
*/
public function identify(array $message)
{
return $this->write($message);
}
/**
* Tags traits about the group.
*
* @param array $message
* @return [boolean] whether the group call succeeded
*/
public function group(array $message)
{
return $this->write($message);
}
/**
* Tracks a page view.
*
* @param array $message
* @return [boolean] whether the page call succeeded
*/
public function page(array $message)
{
return $this->write($message);
}
/**
* Tracks a screen view.
*
* @param array $message
* @return [boolean] whether the screen call succeeded
*/
public function screen(array $message)
{
return $this->write($message);
}
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public function alias(array $message)
{
return $this->write($message);
}
/**
* Writes the API call to a file as line-delimited json
* @param [array] $body post body content.
* @return [boolean] whether the request succeeded
*/
private function write($body)
{
if (!$this->file_handle) {
return \false;
}
$content = \json_encode($body);
$content .= "\n";
return \fwrite($this->file_handle, $content) == \strlen($content);
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace ps_metrics_module_v4_0_5;
class Segment_Consumer_ForkCurl extends Segment_QueueConsumer
{
protected $type = "ForkCurl";
/**
* Creates a new queued fork consumer which queues fork and identify
* calls before adding them to
* @param string $secret
* @param array $options
* boolean "debug" - whether to use debug output, wait for response.
* number "max_queue_size" - the max size of messages to enqueue
* number "batch_size" - how many messages to send in a single request
*/
public function __construct($secret, $options = array())
{
parent::__construct($secret, $options);
}
/**
* Make an async request to our API. Fork a curl process, immediately send
* to the API. If debug is enabled, we wait for the response.
* @param array $messages array of all the messages to send
* @return boolean whether the request succeeded
*/
public function flushBatch($messages)
{
$body = array("batch" => $messages);
$payload = \json_encode($body);
# Escape for shell usage.
$payload = \escapeshellarg($payload);
$secret = $this->secret;
$protocol = $this->ssl() ? "https://" : "http://";
$host = "api.segment.io";
$path = "/v1/import";
$url = $protocol . $host . $path;
$cmd = "curl -u {$secret}: -X POST -H 'Content-Type: application/json'";
$cmd .= " -d " . $payload . " '" . $url . "'";
if (!$this->debug()) {
$cmd .= " > /dev/null 2>&1 &";
}
\exec($cmd, $output, $exit);
if ($exit != 0) {
$this->handleError($exit, $output);
}
return $exit == 0;
}
}

View File

@@ -0,0 +1,145 @@
<?php
namespace ps_metrics_module_v4_0_5;
class Segment_Consumer_Socket extends Segment_QueueConsumer
{
protected $type = "Socket";
private $socket_failed;
/**
* Creates a new socket consumer for dispatching async requests immediately
* @param string $secret
* @param array $options
* number "timeout" - the timeout for connecting
* function "error_handler" - function called back on errors.
* boolean "debug" - whether to use debug output, wait for response.
*/
public function __construct($secret, $options = array())
{
if (!isset($options["timeout"])) {
$options["timeout"] = 0.5;
}
if (!isset($options["host"])) {
$options["host"] = "api.segment.io";
}
parent::__construct($secret, $options);
}
public function flushBatch($batch)
{
$socket = $this->createSocket();
if (!$socket) {
return;
}
$payload = array("batch" => $batch);
$payload = \json_encode($payload);
$body = $this->createBody($this->options["host"], $payload);
return $this->makeRequest($socket, $body);
}
private function createSocket()
{
if ($this->socket_failed) {
return \false;
}
$protocol = $this->ssl() ? "ssl" : "tcp";
$host = $this->options["host"];
$port = $this->ssl() ? 443 : 80;
$timeout = $this->options["timeout"];
try {
# Open our socket to the API Server.
$socket = \pfsockopen($protocol . "://" . $host, $port, $errno, $errstr, $timeout);
# If we couldn't open the socket, handle the error.
if ($errno != 0) {
$this->handleError($errno, $errstr);
$this->socket_failed = \true;
return \false;
}
return $socket;
} catch (\Exception $e) {
$this->handleError($e->getCode(), $e->getMessage());
$this->socket_failed = \true;
return \false;
}
}
/**
* Attempt to write the request to the socket, wait for response if debug
* mode is enabled.
* @param stream $socket the handle for the socket
* @param string $req request body
* @return boolean $success
*/
private function makeRequest($socket, $req, $retry = \true)
{
$bytes_written = 0;
$bytes_total = \strlen($req);
$closed = \false;
# Write the request
while (!$closed && $bytes_written < $bytes_total) {
try {
$written = \fwrite($socket, \substr($req, $bytes_written));
} catch (\Exception $e) {
$this->handleError($e->getCode(), $e->getMessage());
$closed = \true;
}
if (!isset($written) || !$written) {
$closed = \true;
} else {
$bytes_written += $written;
}
}
# If the socket has been closed, attempt to retry a single time.
if ($closed) {
\fclose($socket);
if ($retry) {
$socket = $this->createSocket();
if ($socket) {
return $this->makeRequest($socket, $req, \false);
}
}
return \false;
}
$success = \true;
if ($this->debug()) {
$res = $this->parseResponse(\fread($socket, 2048));
if ($res["status"] != "200") {
$this->handleError($res["status"], $res["message"]);
$success = \false;
}
}
return $success;
}
/**
* Create the body to send as the post request.
* @param string $host
* @param string $content
* @return string body
*/
private function createBody($host, $content)
{
$req = "";
$req .= "POST /v1/import HTTP/1.1\r\n";
$req .= "Host: " . $host . "\r\n";
$req .= "Content-Type: application/json\r\n";
$req .= "Authorization: Basic " . \base64_encode($this->secret . ":") . "\r\n";
$req .= "Accept: application/json\r\n";
$req .= "Content-length: " . \strlen($content) . "\r\n";
$req .= "\r\n";
$req .= $content;
return $req;
}
/**
* Parse our response from the server, check header and body.
* @param string $res
* @return array
* string $status HTTP code, e.g. "200"
* string $message JSON response from the api
*/
private function parseResponse($res)
{
$contents = \explode("\n", $res);
# Response comes back as HTTP/1.1 200 OK
# Final line contains HTTP response.
$status = \explode(" ", $contents[0], 3);
$result = $contents[\count($contents) - 1];
return array("status" => isset($status[1]) ? $status[1] : null, "message" => $result);
}
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,129 @@
<?php
namespace ps_metrics_module_v4_0_5;
abstract class Segment_QueueConsumer extends Segment_Consumer
{
protected $type = "QueueConsumer";
protected $queue;
protected $max_queue_size = 1000;
protected $batch_size = 100;
/**
* Store our secret and options as part of this consumer
* @param string $secret
* @param array $options
*/
public function __construct($secret, $options = array())
{
parent::__construct($secret, $options);
if (isset($options["max_queue_size"])) {
$this->max_queue_size = $options["max_queue_size"];
}
if (isset($options["batch_size"])) {
$this->batch_size = $options["batch_size"];
}
$this->queue = array();
}
public function __destruct()
{
# Flush our queue on destruction
$this->flush();
}
/**
* Tracks a user action
*
* @param array $message
* @return boolean whether the track call succeeded
*/
public function track(array $message)
{
return $this->enqueue($message);
}
/**
* Tags traits about the user.
*
* @param array $message
* @return boolean whether the identify call succeeded
*/
public function identify(array $message)
{
return $this->enqueue($message);
}
/**
* Tags traits about the group.
*
* @param array $message
* @return boolean whether the group call succeeded
*/
public function group(array $message)
{
return $this->enqueue($message);
}
/**
* Tracks a page view.
*
* @param array $message
* @return boolean whether the page call succeeded
*/
public function page(array $message)
{
return $this->enqueue($message);
}
/**
* Tracks a screen view.
*
* @param array $message
* @return boolean whether the screen call succeeded
*/
public function screen(array $message)
{
return $this->enqueue($message);
}
/**
* Aliases from one user id to another
*
* @param array $message
* @return boolean whether the alias call succeeded
*/
public function alias(array $message)
{
return $this->enqueue($message);
}
/**
* Adds an item to our queue.
* @param mixed $item
* @return boolean whether the queue has room
*/
protected function enqueue($item)
{
$count = \count($this->queue);
if ($count > $this->max_queue_size) {
return \false;
}
$count = \array_push($this->queue, $item);
if ($count > $this->batch_size) {
$this->flush();
}
return \true;
}
/**
* Flushes our queue of messages by batching them to the server
*/
public function flush()
{
$count = \count($this->queue);
$success = \true;
while ($count > 0 && $success) {
$batch = \array_splice($this->queue, 0, \min($this->batch_size, $count));
$success = $this->flushBatch($batch);
$count = \count($this->queue);
}
return $success;
}
/**
* Flushes a batch of messages.
* @param [type] $batch [description]
* @return [type] [description]
*/
abstract function flushBatch($batch);
}

View File

@@ -0,0 +1,11 @@
<?php
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;