# Overview The Aerospike <a href="http://www.aerospike.com/docs/architecture/clients.html" target="_doc">client</a> for PHP enables your application to work with an Aerospike <a href="http://www.aerospike.com/docs/architecture/distribution.html" target="_doc">cluster</a> as its <a href="http://www.aerospike.com/docs/guide/kvs.html" target="_doc">key-value store</a>. The <a href="http://www.aerospike.com/docs/architecture/data-model.html" target="_doc">Data Model</a> document gives further details on how data is organized in the cluster. ## Generating documentation with phpDocumentor The Aerospike client for PHP is written as a C module, but we have added a PHP stub under `docs/phpdoc`. You can import the stub into your IDE for auto-completion, or build the API documentation using [phpDocumentor](https://phpdoc.org/) ``` phpdoc run -v -d phpdoc/ -t html/ ``` ## Aerospike Session Handler The Aerospike PHP client provides a custom session handler that can be used to store user sessions in Aerospike. A set and namespace must be given to act as the container for the sessions. The session ID is used as the primary key of the record containing the session. The key-value pairs in the `$_SESSION` object are stored in the matching record. The value of `session.gc_maxlifetime` is used as the record ttl. `session.save_handler string` Set to _aerospike_ to enable sessions support. `session.save_path string` A string formatted as **ns|set|addr:port\[,addr:port\[,...\]\]**. for example "test|sess|127.0.0.1:3000" As with the *$config* of the constructor, the host info of just one cluster node is necessary. ## Configuration in a Web Server Context Initializing the client to a cluster is a costly operation, so ideally it should be reused for the multiple requests that the same PHP process will handle (as is the case for mod\_php and fastCGI). The developer can determine whether the constructor will use persistent connections by way of an optional boolean argument. After the first time `Aerospike::__construct__()` is called within the process, the client will be stored for reuse by subsequent requests, if persistent connections were indicated. With persistent connections, the methods _reconnect()_ and _close()_ do not actually close the connection. Each Aerospike client opens 2*N connections to the cluster, where N is the number of nodes in that cluster, and a connection simply costs a file descriptor on the server-side. Depending on the number of web servers and PHP processes on each server, you may need to adjust the [proto-fd-max](http://www.aerospike.com/docs/reference/configuration/#proto-fd-max) server config parameter and the OS limits to account for the necessary number of [file descriptors](http://www.aerospike.com/docs/operations/troubleshoot/startup/#not-enough-file-descriptors-error-in-log). On the client side, the web server should be configured to reduce the frequency in which new clients are created. Historically, the `max_requests` for mod\_php and FPM was set low to combat memory leaks. PHP has been stable on memory for a long while, so the correct configuration would be to have fewer processes, and let each of them handle a high number of requests. This reduces the process initialization overhead, and the overall number of connections on the web server. Monitoring the memory consumption of the PHP processes allows the `max_requests` to be raised safely to an efficient, stable value. The client keeps track of changes at the server-side through a [cluster tending](http://www.aerospike.com/docs/architecture/clustering.html) thread. In a web server context, a single client can handle cluster tending and share its state through a shared-memory segment. To enable shm cluster tending, the developer can set the `aerospike.shm.use` ini config to `true`, or at the constructor through its config. ## Halting a Stream Halting a _query()_ or _scan()_ result stream can be done by returning (an explicit) boolean **false** from the callback. The client will then close the sockets to the nodes of the cluster, halting the stream of records. ## How PHP Data is stored in Aerospike The PHP Data types of Integer, String, Float, Array map directly to Aerospike data types. All other data types will be handled through serialization. See the "Handling Unsupported Types" sections for details. The following table shows how data is stored |PHP Data Type | Aerospike Data type| |-----------------|--------------------| |Integer | integer | |Float | float | |String | string | |Array | (list or map)* | |\Aerospike\Bytes | blob | Depending on the structure of the array in PHP, the data will be either stored as an as_list, or an as_map. If the array has only integer keys, which are sequential and begin with 0, it will be stored as `as_list`. Otherwise it will be stored as `as_map`. For example ["a", "b", "c"] would be stored as a list, whereas ["a" => "1", "b", "c"=>"d"] would be stored as as\_map. Both list and map datatypes from the server will be converted into PHP arrays ## Handling Unsupported Types See: [Data Types](http://www.aerospike.com/docs/guide/data-types.html) See: [as_bytes.h](https://github.com/aerospike/aerospike-common/blob/master/src/include/aerospike/as_bytes.h) * Allow the user to register their own serializer/deserializer method - OPT\_SERIALIZER : SERIALIZER\_PHP (default), SERIALIZER\_NONE, SERIALIZER\_USER * when a write operation runs into types that do not map directly to Aerospike DB types it checks the OPT\_SERIALIZER setting: - if SERIALIZER\_NONE it returns an Aerospike::ERR\_PARAM error - if SERIALIZER\_PHP it calls the PHP serializer, sets the object's as\_bytes\_type to AS\_BYTES_PHP. This is the default behavior. - if SERIALIZER\_USER it calls the PHP function the user registered a callback with Aerospike::setSerializer(), and sets as\_bytes\_type to AS\_BYTES\_BLOB * when a read operation extracts a value from an AS\_BYTES type bin: - if it’s a AS\_BYTES\_PHP use the PHP unserialize function - if it’s a AS\_BYTES\_BLOB and the user registered a callback with Aerospike::setDeserializer() call that function, otherwise convert it to \Aerospike\Bytes **Warning** Storing \Aerospike\Bytes results in information being stored as: AS\_BYTES\_BLOB . Subsequent retrieval of this data will be passed to a user specified deserializer if it has been registered. Storing \Aerospike\Bytes and using a user specified deserializer will likely cause errors, and is strongly discouraged. **Warning:** Strings in PHP are a binary-safe structure that allows for the null-byte (**\0**) to be stored inside the string, not just at its end. Binary-strings with this characteristic are created by calling functions such as serialize() and gzdeflate(). As a result, the Aerospike client may truncate the resulting strings. On the Aerospike server, strings are a data type that can be queried using a secondary index, while bytes are a data type that is only used for storage. The developer should wrap binary-string with an object to distinguish them. This allows the serializer to behave in the correct manner. ### Example: ```php require('autoload.php'); $client = new Aerospike(['hosts'=>[['addr'=>'127.0.0.1', 'port'=>3000]]]); $str = 'Glagnar\'s Human Rinds, "It\'s a bunch\'a munch\'a crunch\'a human!'; $deflated = new \Aerospike\Bytes(gzdeflate($str)); $wrapped = new \Aerospike\Bytes("trunc\0ated"); $key = $client->initKey('test', 'demo', 'wrapped-bytes'); $status = $client->put($key, ['unwrapped'=>"trunc\0ated", 'wrapped'=> $wrapped, 'deflated' => $deflated]); if ($status !== Aerospike::OK) { die($client->error()); } $client->get($key, $record); $wrapped = \Aerospike\Bytes::unwrap($record['bins']['wrapped']); $deflated = $record['bins']['deflated']; $inflated = gzinflate($deflated->s); echo "$inflated\n"; echo "wrapped binary-string: "; var_dump($wrapped); $unwrapped = $record['bins']['unwrapped']; echo "The binary-string that was given to put() without a wrapper: $unwrapped\n"; $client->close(); ``` Outputs: ``` Glagnar's Human Rinds, "It's a bunch'a munch'a crunch'a human! wrapped binary-string: string(10) "truncated" The binary-string that was given to put() without a wrapper: trunc ``` ## Differences from the previous Aerospike PHP 5 Client: - LDT Support has been removed. - Type checking in general is stricter for method parameters. If you are not sure whether an argument to a function is an integer or a string, we recommend casting it to the type specified by the method. Running with strict_types enabled may help to catch some issues. - An exception will be raised if the constructor fails to connect to the cluster. - \Aerospike\Bytes will be stored to the server as type AS\_BYTES\_BLOB instead of AS\_BYTES\_PHP. This change allows better compatability with other clients. - Correspondingly, data stored in the server as AS\_BYTES\_BLOB will be returned as Aerospike\Bytes, if no deserializer has been registered. The Previous version of the Aerospike PHP Client returned a string if AS_BYTES_BLOB was encountered with no registered deserializer. - Support for PHP versions < 7 has been removed. - The INI entry `aerospike.serializer` now takes an integer value. 0 for No Serializer, 1 for default PHP serialization, and 2 for user specified serializer. See [Configuration](phpdoc/aerospike.php) for additional information on the code values. - The constructor will no longer attempt to create a unique SHM key for the user. If a key is not specified in the shm configuration array, the default value will be used. A key provided in the constructor takes precedence over a value specified by INI. - The layout of the shared memory used by the client when using an SHM key has changed. The default key has changed as well in order to prevent accidental sharing between new and old clients. - The formatting of the response from an info call may have changed. It now includes the request at the beginning of the response. - When using initKey with a digest, the digest must now be exactly 20 bytes. - The integer values of the `Aerospike::LOG_LEVEL_*` constants have changed. This should not effect the user unless they were providing log levels as integers rather than using the constants. - `Aerospike::LOG_LEVEL_OFF` has been removed. It no longer had any effect. ## PHP Version Support PHP >= 7 is supported by this client. ## Further Reading - [How does the Aerospike client find a node](https://discuss.aerospike.com/t/how-does-aerospike-client-find-a-node/706)