aws elasticache with php - unable to set key/value pair - php

I am able to connect to my elasticache cluster like so:
$awsElasticache = new ElastiCacheClient(CredentialProvider::atsDefaultConfigConstructor(false, false));
$clusterResult = $awsElasticache->describeCacheClusters(array('CacheClusterId'=>'my_cluster'));
When I print $clusterResult, I get info about the cluster, good.
But how can I actually interact with the endpoint to set key/value pairs?
I am trying this without success:
$this->mem = new Memcached();
$this->mem->addServer($this->endPoint,11211);
$this->mem->set('myKey','myValue',3600);
$result = $this->mem->get('myKey');
echo $result;
I get nothing printed from $result.
I am confused about which object to use to set and get key/value pairs.

To set key/value pair in Memcached, always extend the time of expiry from current time.
Try this
$this->mem = new Memcached();
$this->mem->addServer($this->endPoint,11211);
$expires = Carbon::now()->addMinutes(10);
$this->mem->set('myKey','myValue', $expires);
$result = $this->mem->get('myKey');
echo $result;
NOTE: For some reason, Memcached works best with Carbon time
See https://artisansweb.net/work-php-datetime-using-carbon/ on how to setup and use Carbon on your current project

Related

Using PHP For Each to save individual results to Redis

I have some code running on my website that uses API calls to pull events from a calendar and show them on my website. The code is fairly simple overall, and works well, however to prevent the code from running every time the page loads, I'm using PHP Redis to save the key data to a Redis List, then a cronjob to run the php code that uses the Redis List to fetch the information from the calendar API, and save the information to Redis.
Everything works fine, except I am using foreach to run through each instance of the Redis List; and it keeps running through all the entries but saving only the last one. What can I do to fix this?
My code:
<?php
function redis_calendar_fetch() {
$redisObj1 = new Redis();
$redisObj1 -> connect('localhost', 6379, 2.5, NULL, 150 );
date_default_timezone_set('America/Edmonton');
$fetcharray = $redisObj1-> smembers('fetch_list');
$effectiveDate = date('Y-m-d', strtotime('+12 months'));
$application_id = "REDACTED";
$secret = "REDACTED";
$fafull = array();
foreach($fetcharray as $faraw) {
$fa1 = json_decode($faraw);
$fa2 = json_decode(json_encode($fa1), true);
$fafull[] = $fa2;
}
$redisObj1 -> close(); // This code all works perfectly, and returns the Redis List results in an array that can be used by foreach
foreach($fafull as $fa) {
$redisObj = new Redis();
$redisObj -> connect('localhost', 6379, 2.5, NULL, 150 );
// After this, I run through all the array data, pull data & process it properly. I have omitted this from this question because it is long and arduous, and runs perfectly fine.
// Right before this, an array called $redisarray is created that contains all the relevant event data //
$redisarrayfixed = json_encode($redisarray);
$redisObj->set($key, $redisarrayfixed);
$redisObj -> close();
// If I put a line here saying 'return = $redisarrayfixed', the code runs only the first instance of the array and stops. If I omit this, it runs through all of them, but only saves the last one
}
}
redis_calendar_fetch();
As mentioned, I then use a cronjob to run this code every 30 minutes, and I have a separate piece of php code that handles the shortcode & fetches the proper saved events for the proper page.
My concern solely is with the foreach($fafull as $fa), which only saves the final result to Redis. Is there a better way to force each array instance to save?
For performance, you might want to keep just one instance of a redis connection active.
Secondly, it's only going to save the final result because on each iteration, you are using the same $key. It seems like what you want to do is iterate and push to an array, then at the end, save it entirely.
Example of how I'm understanding this;
$redisObj = new Redis();
$redisObj -> connect('localhost', 6379, 2.5, NULL, 150 );
$someArray = array();
foreach($fafull as $fa) {
$redisarrayfixed = json_encode($redisarray);
array_push($someArray, $redisarrayfixed);
}
$redisObj->set($key, $someArray);
$redisObj -> close();

Docusign API PHP TemplatesApi::updateDocument FORMAT_CONVERSION_ERROR

I'm trying to update a template document via PHP API using this: https://github.com/docusign/docusign-php-client/blob/master/src/Api/TemplatesApi.php#L4946
I get one of two errors depending on if I set the apply_document_fields option.
Without it set, I get UNSPECIFIED ERROR Value cannot be null.\r\nParameter name: fileBytes. However, if I view the request body before sending, document_base_64 is set as expected.
With apply_document_fields set 'true' (actual boolean value is not supported), I get FORMAT_CONVERSION_ERROR The data could not be converted.
Either way, it seems like the document data is not getting sent correctly, but I can't figure out how I'm supposed to be sending it. Here's my code:
public static function updateTemplateWithDocument(string $documentId, string $templateId, $documentBody = null)
{
$api = My_Service_Docusign::getInstance();
$templatesApi = new DocuSign\eSign\Api\TemplatesApi($api->getAuth());
$document = new \DocuSign\eSign\Model\Document();
$document->setDocumentBase64(base64_encode($documentBody));
// Got an error reusing $documentId, so I'm incrementing it now
$document->setDocumentId((string) (((int)$documentId) + 1));
$def = new DocuSign\eSign\Model\EnvelopeDefinition();
$def->setDocuments(array($document));
$opts = new \DocuSign\eSign\Api\TemplatesApi\UpdateDocumentOptions();
// Different behavior with this set vs not
$opts->setApplyDocumentFields('true');
$res = $tmpApi->updateDocument($api->getAccountId(), $documentId, $templateId, $def, $opts);
return $res;
}
Unfortunately, DocuSign support doesn't support their API :-(
I figured out I need to use TemplatesApi::updateDocuments (plural) instead, which also allows me to reuse the documentId.

PHP: How to get current memcached object persistence id

Is there any way to get current memcached instance persistence id in
PHP?
// Some place in code
$persistence = 'my servername_' . md5(unique());
$memcachedObject = new Memcached($persistence);
And then somewhere else something like:
$memcachedObject->getPersistenceId();

PHP - Syncing MySQL Contacts with Exchange

As part of a PHP webapp I have MySQL contacts table. It is integrated throughout the app, allowing you add a contact, edit a contact or add a contact as a relation to another table. However, currently it is self-contained. The company would like it to sync with Exchange, so that contacts added to Exchange will show up on the webapp and contacts added on the webapp will show up through Exchange.
So I have two problems: 1) communicating with Exchange 2) syncing with Exchange.
As far as the basic communication goes, it looks like this library will be able to manage it https://github.com/jamesiarmes/php-ews. However, I am quite lost as to how to manage syncing and don't where to start.
The build-in way to sync items is via function called SyncFolderItems. Basically to Exchange everything, including contacts is a folder, so you'll just pass CONTACTS as DistinguishedFolderId in your sync request.
The sync works by donloading all the items for given account in batches of max 512 elements and after each batch it gives you SyncState as a refernce point for Exchange to know where you left off. So it gives you ability to do incremental sync.
Now, that's one way of course, meaning Exchange -> Your DB. The other way it aeound you should preform atomic updates/request - the moment you change/add/delete item form your db you should issue adequate request to Exchange server to keep data in sync, elese it'll be overwritten on your next SyncFolderItems.
You can read up more on SyncFolderItems # MSDN
If you'd like to see example of SyncFolderItems you can take a look # python version of EWSWrapper, it's been added in recently. Although it's python, you can still get the basic idea how to construct the request / handle response.
Hope this helps :)
I am aware that this topic is pretty old. However, for future reference find a solution below. It is using the above-mentioned library php-ews.
I have also just added this to the official php-ews wiki: https://github.com/jamesiarmes/php-ews/wiki/Calendar:-Synchronization
// Define EWS
$ews = new ExchangeWebServices($host, $username, $password, $version);
// fill with string from last sync
$sync_state = null;
$request = new EWSType_SyncFolderItemsType;
$request->SyncState = $sync_state;
$request->MaxChangesReturned = 512;
$request->ItemShape = new EWSType_ItemResponseShapeType;
$request->ItemShape->BaseShape = EWSType_DefaultShapeNamesType::ALL_PROPERTIES;
$request->SyncFolderId = new EWSType_NonEmptyArrayOfBaseFolderIdsType;
$request->SyncFolderId->DistinguishedFolderId = new EWSType_DistinguishedFolderIdType;
$request->SyncFolderId->DistinguishedFolderId->Id = EWSType_DistinguishedFolderIdNameType::CALENDAR;
$response = $ews->SyncFolderItems($request);
$sync_state = $response->ResponseMessages->SyncFolderItemsResponseMessage->SyncState;
$changes = $response->ResponseMessages->SyncFolderItemsResponseMessage->Changes;
// created events
if(property_exists($changes, 'Create')) {
foreach($changes->Create as $event) {
$id = $event->CalendarItem->ItemId->Id;
$change_key = $event->CalendarItem->ItemId->ChangeKey;
$start = $event->CalendarItem->Start;
$end = $event->CalendarItem->End;
$subject = $event->CalendarItem->Subject;
}
}
// updated events
if(property_exists($changes, 'Update')) {
foreach($changes->Update as $event) {
$id = $event->CalendarItem->ItemId->Id;
$change_key = $event->CalendarItem->ItemId->ChangeKey;
$start = $event->CalendarItem->Start;
$end = $event->CalendarItem->End;
$subject = $event->CalendarItem->Subject;
}
}
// deleted events
if(property_exists($changes, 'Delete')) {
foreach($changes->Delete as $event) {
$id = $event->CalendarItem->ItemId->Id;
$change_key = $event->CalendarItem->ItemId->ChangeKey;
$start = $event->CalendarItem->Start;
$end = $event->CalendarItem->End;
$subject = $event->CalendarItem->Subject;
}
}

delete cache by prefix in apc / memcache / eaccelerator

Let's assume I have these variables saved in apc, memcached and eaccelerator:
article_1_0
article_1_1
article_3_2
article_3_3
article_2_4
How can I delete all cached variables that starts with article_3_ (they can reach up to 10000) ?
is there any way to list the cached variables ?
The slow solution
For APC:
$iterator = new APCIterator('user', '#^article_3_#', APC_ITER_KEY);
foreach($iterator as $entry_name) {
apc_delete($entry_name);
}
For eaccelerator:
foreach(eaccelerator_list_keys() as $name => $infos) {
if (preg_match('#^article_3_#', $name)) {
eaccelerator_rm($name);
}
}
For memcached, look at #rik's answer
The proper solution
The general solution for expiring multiple keys at once is to namespace them. For expiring them, you just have to change the namespace:
Say you have a group of keys "article_3_1", "article_3_2", .... You can store them like this:
$ns = apc_fetch('article_3_namespace');
apc_store($ns."_article_3_1", $value);
apc_store($ns."_article_3_2", $value);
Fetch them like this:
$ns = apc_fetch('article_3_namespace');
apc_fetch($ns."_article_3_1");
And expire them all by just incrementing the namespace:
apc_inc('article_3_namespace');
Although the docs say APCIterator is available in apc >= 3.1.1, I'm on several systems that claim to have apc 3.1.9, however there is no APCIterator present. If you don't have APCIterator at your disposal, give something like this a whirl:
$aCacheInfo = apc_cache_info('user');
foreach($aCacheInfo['cache_list'] as $_aCacheInfo)
if(strpos($_aCacheInfo['info'], 'key_prefix:') === 0)
apc_delete($_aCacheInfo['info']);
In this example we're checking for a prefix in the key, but you could use preg_match et. al and achieve something closer to what APCIterator provides.
There is a way to retrieve all keys from memcache but it's very expensive.
If there is possibility to use alternatives for memcached, scache supports structured keyspaces. With it you could store data to nested paths :
scache_shset($conn, 'article/1/0', $data10);
scache_shset($conn, 'article/3/0', $data30);
scache_shset($conn, 'article/3/1', $data31);
and eventually destroy data by deleting the parent node
scache_shunset($conn, 'article/3');
There is an APCIterator which helps you search through the keys in APC.
Instantiate the APCIterator.
APCIterator::valid() means that there are keys still to iterate trough. APCIterator::key() returns you the apc key. APCIterator::next() moves the iterator position to the next item.
// APC
$iterator = new APCIterator('user', '/^article_3_/');
while($iterator->valid()) {
apc_delete($iterator->key());
// You can view the info for this APC cache value and so on by using
// $iterator->current() which is array
$iterator->next();
}
For memcache you can use Memcached and use getAllKeys method
// Memcached
$m = new Memcached();
$m->addServer('mem1.domain.com', 11211);
$items = $m->getAllKeys();
foreach($items as $item) {
if(preg_match('#^article_3_#', $item)) {
$m->delete($item);
}
}

Categories