Giter Site home page Giter Site logo

azure-sdk-for-php's Introduction

Build Status Latest Stable Version

Microsoft Azure SDK for PHP

This project provides a set of PHP client libraries that make it easy to access Microsoft Azure tables, blobs, queues, service bus (queues and topics), service runtime and service management APIs. For documentation on how to host PHP applications on Microsoft Azure, please see the Microsoft Azure PHP Developer Center.

Important Annoucement

As of February 2021, the Azure SDK for PHP has entered a retirement phase and is no longer officially supported by Microsoft. This repository will no longer be maintained.

If you prefer to work in PHP, you can directly call the Azure REST API in PHP

NOTE: Please note that the Azure Storage SDK for PHP will be separately maintained in its own repo

For more details, please refer to our support policy here

Features

  • Tables
  • Blobs
    • create, list, and delete containers, work with container metadata and permissions, list blobs in container
    • create block and page blobs (from a stream or a string), work with blob blocks and pages, delete blobs
    • work with blob properties, metadata, leases, snapshot a blob
    • REST API Version: see https://github.com/Azure/azure-storage-php
  • Storage Queues
  • Service Bus
    • Queues: create, list and delete queues; send, receive, unlock and delete messages
    • Topics: create, list, and delete topics; create, list, and delete subscriptions; send, receive, unlock and delete messages; create, list, and delete rules
  • Service Runtime
    • discover addresses and ports for the endpoints of other role instances in your service
    • get configuration settings and access local resources
    • get role instance information for current role and other role instances
    • query and set the status of the current role
    • REST API Version: 2011-03-08
  • Service Management
    • storage accounts: create, update, delete, list, regenerate keys
    • affinity groups: create, update, delete, list, get properties
    • locations: list
    • hosted services: create, update, delete, list, get properties
    • deployment: create, get, delete, swap, change configuration, update status, upgrade, rollback
    • role instance: reboot, reimage
    • REST API Version: 2011-10-01
  • Media Services
    • Connection
    • Ingest asset, upload files
    • Encoding / process asset, create job, job templates
    • Manage media services entities: create / update / read / delete / get list
    • Delivery SAS and Streaming media content
    • Dynamic encryption: AES and DRM (PlayReady/Widevine/FairPlay) with and without Token restriction
    • Scale encoding reserved unit type
    • Live streaming: live encoding and pass-through channels, programs and all their operations
    • REST API Version: 2.13

Getting Started

Download Source Code

To get the source code from GitHub, type

git clone https://github.com/Azure/azure-sdk-for-php.git
cd ./azure-sdk-for-php

Note

The recommended way to resolve dependencies is to install them using the Composer package manager.

Install via Composer

  • Create a file named composer.json in the root of your project and add the following code to it:

    {
        "require": {
            "microsoft/windowsazure": "^0.5"
        }
    }
  • Download composer.phar in your project root.

  • Open a command prompt and execute this in your project root

    php composer.phar install
    

    Note

    On Windows, you will also need to add the Git executable to your PATH environment variable.

Usage

Getting Started

There are four basic steps that have to be performed before you can make a call to any Microsoft Azure API when using the libraries.

  • First, include the autoloader script:

    require_once "vendor/autoload.php";
  • Include the namespaces you are going to use.

    To create any Microsoft Azure service client you need to use the ServicesBuilder class:

    use WindowsAzure\Common\ServicesBuilder;

    To process exceptions you need:

    use WindowsAzure\Common\ServiceException;
  • To instantiate the service client you will also need a valid connection string. The format is:

    • For accessing a live storage service (tables, blobs, queues):

      DefaultEndpointsProtocol=[http|https];AccountName=[yourAccount];AccountKey=[yourKey]
      
    • For accessing the emulator storage:

      UseDevelopmentStorage=true
      
    • For accessing the Service Bus:

      Endpoint=[yourEndpoint];SharedSecretIssuer=[yourWrapAuthenticationName];SharedSecretValue=[yourWrapPassword]
      

      Where the Endpoint is typically of the format https://[yourNamespace].servicebus.windows.net.

    • For accessing Service Management APIs:

      SubscriptionID=[yourSubscriptionId];CertificatePath=[filePathToYourCertificate]
      
  • Instantiate a "REST Proxy" - a wrapper around the available calls for the given service.

    • For the Storage services:

      $tableRestProxy = ServicesBuilder::getInstance()->createTableService($connectionString);
      $blobRestProxy = ServicesBuilder::getInstance()->createBlobService($connectionString);
      $queueRestProxy = ServicesBuilder::getInstance()->createQueueService($connectionString);
    • For Service Bus:

      $serviceBusRestProxy = ServicesBuilder::getInstance()->createServiceBusService($connectionString);
    • For Service Management:

      $serviceManagementRestProxy = ServicesBuilder::getInstance()->createServiceManagementService($connectionString);
    • For Media Services:

      // 1 - Instantiate the credentials
      $credentials = new AzureAdTokenCredentials(
          '<tenant domain name>',
          new AzureAdClientSymmetricKey('<service principal client id>', '<service principal client key>'),
          AzureEnvironments::AZURE_CLOUD_ENVIRONMENT());
      
      // 2 - Instantiate a token provider
      $provider = new AzureAdTokenProvider($credentials);
      
      // 3 - Connect to Azure Media Services
      $mediaServicesRestProxy = ServicesBuilder::getInstance()->createMediaServicesService(new MediaServicesSettings('<rest api endpoint>', $provider));

      You can find more examples for Media Services Authentication on the examples folder.

Table Storage

The following are examples of common operations performed with the Table service. For more please read How-to use the Table service.

Create a table

To create a table call createTable:

try {
  // Create table.
  $tableRestProxy->createTable("mytable");
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Error Codes and Messages for Tables

Insert an entity

To add an entity to a table, create a new Entity object and pass it to TableRestProxy->insertEntity. Note that when you create an entity you must specify a PartitionKey and RowKey. These are the unique identifiers for an entity and are values that can be queried much faster than other entity properties. The system uses PartitionKey to automatically distribute the table’s entities over many storage nodes.

use MicrosoftAzure\Storage\Table\Models\Entity;
use MicrosoftAzure\Storage\Table\Models\EdmType;

$entity = new Entity();
$entity->setPartitionKey("pk");
$entity->setRowKey("1");
$entity->addProperty("PropertyName", EdmType::STRING, "Sample");

try{
  $tableRestProxy->insertEntity("mytable", $entity);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Query entities

To query for entities you can call queryEntities. The subset of entities you retrieve will be determined by the filter you use (for more information, see Querying Tables and Entities). You can also provide no filter at all.

$filter = "RowKey eq '2'";

try {
  $result = $tableRestProxy->queryEntities("mytable", $filter);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

$entities = $result->getEntities();

foreach($entities as $entity){
  echo $entity->getPartitionKey().":".$entity->getRowKey()."<br />";
}

Blob Storage

To get started using the Blob service you must include the BlobService and BlobSettings namespaces and set the ACCOUNT_NAME and ACCOUNT_KEY configuration settings for your credentials. Then you instantiate the wrapper using the BlobService factory.

The following are examples of common operations performed with the Blob serivce. For more please read How-to use the Blob service.

Create a container

// OPTIONAL: Set public access policy and metadata.
// Create container options object.
$createContainerOptions = new CreateContainerOptions();

// Set public access policy. Possible values are
// PublicAccessType::CONTAINER_AND_BLOBS and PublicAccessType::BLOBS_ONLY.
// CONTAINER_AND_BLOBS: full public read access for container and blob data.
// BLOBS_ONLY: public read access for blobs. Container data not available.
// If this value is not specified, container data is private to the account owner.
$createContainerOptions->setPublicAccess(PublicAccessType::CONTAINER_AND_BLOBS);

// Set container metadata
$createContainerOptions->addMetaData("key1", "value1");
$createContainerOptions->addMetaData("key2", "value2");

try {
  // Create container.
  $blobRestProxy->createContainer("mycontainer", $createContainerOptions);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Error Codes and Messages for Blobs

For more information about container ACLs, see Set Container ACL (REST API).

Upload a blob

To upload a file as a blob, use the BlobRestProxy->createBlockBlob method. This operation will create the blob if it doesn’t exist, or overwrite it if it does. The code example below assumes that the container has already been created and uses fopen to open the file as a stream.

$content = fopen("myfile.txt", "r");
$blob_name = "myblob";

try {
  //Upload blob
  $blobRestProxy->createBlockBlob("mycontainer", $blob_name, $content);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

While the example above uploads a blob as a stream, a blob can also be uploaded as a string.

List blobs in a container

To list the blobs in a container, use the BlobRestProxy->listBlobs method with a foreach loop to loop through the result. The following code outputs the name and URI of each blob in a container.

try {
  // List blobs.
  $blob_list = $blobRestProxy->listBlobs("mycontainer");
  $blobs = $blob_list->getBlobs();

  foreach($blobs as $blob)
  {
    echo $blob->getName().": ".$blob->getUrl()."<br />";
  }
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Storage Queues

To get started using the Queue service you must include the QueueService and QueueSettings namespaces and set the ACCOUNT_NAME and ACCOUNT_KEY configuration settings for your credentials. Then you instantiate the wrapper using the QueueService factory.

The following are examples of common operations performed with the Queue serivce. For more please read How-to use the Queue service.

Create a queue

A QueueRestProxy object lets you create a queue with the createQueue method. When creating a queue, you can set options on the queue, but doing so is not required.

$createQueueOptions = new CreateQueueOptions();
$createQueueOptions->addMetaData("key1", "value1");
$createQueueOptions->addMetaData("key2", "value2");

try {
  // Create queue.
  $queueRestProxy->createQueue("myqueue", $createQueueOptions);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Error Codes and Messages for Queues

Add a message to a queue

To add a message to a queue, use QueueRestProxy->createMessage. The method takes the queue name, the message text, and message options (which are optional). For compatibility with others you may need to base64 encode message.

try {
  // Create message.
  $msg = "Hello World!";
  // optional: $msg = base64_encode($msg);
  $queueRestProxy->createMessage("myqueue", $msg);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Peek at the next message

You can peek at a message (or messages) at the front of a queue without removing it from the queue by calling QueueRestProxy->peekMessages.

// OPTIONAL: Set peek message options.
$message_options = new PeekMessagesOptions();
$message_options->setNumberOfMessages(1); // Default value is 1.

try {
  $peekMessagesResult = $queueRestProxy->peekMessages("myqueue", $message_options);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

$messages = $peekMessagesResult->getQueueMessages();

// View messages.
$messageCount = count($messages);
if($messageCount <= 0){
  echo "There are no messages.<br />";
}
else{
  foreach($messages as $message)  {
    echo "Peeked message:<br />";
    echo "Message Id: ".$message->getMessageId()."<br />";
    echo "Date: ".date_format($message->getInsertionDate(), 'Y-m-d')."<br />";
    echo "Message text: ".$message->getMessageText()."<br /><br />";
  }
}

De-queue the next message

Your code removes a message from a queue in two steps. First, you call QueueRestProxy->listMessages, which makes the message invisible to any other code reading from the queue. By default, this message will stay invisible for 30 seconds (if the message is not deleted in this time period, it will become visible on the queue again). To finish removing the message from the queue, you must call QueueRestProxy->deleteMessage.

// Get message.
$listMessagesResult = $queueRestProxy->listMessages("myqueue");
$messages = $listMessagesResult->getQueueMessages();
$message = $messages[0];

// Process message

// Get message Id and pop receipt.
$messageId = $message->getMessageId();
$popReceipt = $message->getPopReceipt();

try {
  // Delete message.
  $queueRestProxy->deleteMessage("myqueue", $messageId, $popReceipt);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Service Bus Queues

The current PHP Service Bus APIs only support ACS connection strings. You need to use PowerShell to create a new ACS Service Bus namespace at the present time. First, make sure you have Azure PowerShell installed, then in a PowerShell command prompt, run

Add-AzureAccount # this will sign you in
New-AzureSBNamespace -CreateACSNamespace $true -Name 'mytestbusname' -Location 'West US' -NamespaceType 'Messaging'

If it is sucessful, you will get the connection string in the PowerShell output. If you get connection errors with it and the conection string looks like Endpoint=sb://..., change it to Endpoint=https://...

Create a Queue

try {
  $queueInfo = new QueueInfo("myqueue");

  // Create queue.
  $serviceBusRestProxy->createQueue($queueInfo);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Error Codes and Messages

Send a Message

To send a message to a Service Bus queue, your application will call the ServiceBusRestProxy->sendQueueMessage method. Messages sent to (and received from ) Service Bus queues are instances of the BrokeredMessage class.

try {
  // Create message.
  $message = new BrokeredMessage();
  $message->setBody("my message");

  // Send message.
  $serviceBusRestProxy->sendQueueMessage("myqueue", $message);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Receive a Message

The primary way to receive messages from a queue is to use a ServiceBusRestProxy->receiveQueueMessage method. Messages can be received in two different modes: ReceiveAndDelete (mark message as consumed on read) and PeekLock (locks message for a period of time, but does not delete).

The example below demonstrates how a message can be received and processed using PeekLock mode (not the default mode).

try {
  // Set the receive mode to PeekLock (default is ReceiveAndDelete).
  $options = new ReceiveMessageOptions();
  $options->setPeekLock(true);

  // Receive message.
  $message = $serviceBusRestProxy->receiveQueueMessage("myqueue", $options);
  echo "Body: ".$message->getBody()."<br />";
  echo "MessageID: ".$message->getMessageId()."<br />";

  // *** Process message here ***

  // Delete message.
  $serviceBusRestProxy->deleteMessage($message);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Service Bus Topics

Create a Topic

try {
  // Create topic.
  $topicInfo = new TopicInfo("mytopic");
  $serviceBusRestProxy->createTopic($topicInfo);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Create a subscription with the default (MatchAll) filter

try {
  // Create subscription.
  $subscriptionInfo = new SubscriptionInfo("mysubscription");
  $serviceBusRestProxy->createSubscription("mytopic", $subscriptionInfo);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Send a message to a topic

Messages sent to Service Bus topics are instances of the BrokeredMessage class.

try {
  // Create message.
  $message = new BrokeredMessage();
  $message->setBody("my message");

  // Send message.
  $serviceBusRestProxy->sendTopicMessage("mytopic", $message);
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Receive a message from a topic

The primary way to receive messages from a subscription is to use a ServiceBusRestProxy->receiveSubscriptionMessage method. Received messages can work in two different modes: ReceiveAndDelete (the default) and PeekLock similarly to Service Bus Queues.

The example below demonstrates how a message can be received and processed using ReceiveAndDelete mode (the default mode).

try {
  // Set receive mode to PeekLock (default is ReceiveAndDelete)
  $options = new ReceiveMessageOptions();
  $options->setReceiveAndDelete();

  // Get message.
  $message = $serviceBusRestProxy->receiveSubscriptionMessage("mytopic",
                                "mysubscription",
                                $options);
  echo "Body: ".$message->getBody()."<br />";
  echo "MessageID: ".$message->getMessageId()."<br />";
} catch(ServiceException $e){
  $code = $e->getCode();
  $error_message = $e->getMessage();
  echo $code.": ".$error_message."<br />";
}

Service Management

Set-up certificates

You need to create two certificates, one for the server (a .cer file) and one for the client (a .pem file). To create the .pem file using OpenSSL, execute this:

openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem

To create the .cer certificate, execute this:

openssl x509 -inform pem -in mycert.pem -outform der -out mycert.cer

List Available Locations

$serviceManagementRestProxy->listLocations();
$locations = $result->getLocations();
foreach($locations as $location){
      echo $location->getName()."<br />";
}

Create a Storage Service

To create a storage service, you need a name for the service (between 3 and 24 lowercase characters and unique within Microsoft Azure), a label (a base-64 encoded name for the service, up to 100 characters), and either a location or an affinity group. Providing a description for the service is optional.

$name = "mystorageservice";
$label = base64_encode($name);
$options = new CreateStorageServiceOptions();
$options->setLocation('West US');

$result = $serviceManagementRestProxy->createStorageService($name, $label, $options);

Create a Cloud Service

A cloud service is also known as a hosted service (from earlier versions of Microsoft Azure). The createHostedServices method allows you to create a new hosted service by providing a hosted service name (which must be unique in Microsoft Azure), a label (the base 64-endcoded hosted service name), and a CreateServiceOptions object which allows you to set the location or the affinity group for your service.

$name = "myhostedservice";
$label = base64_encode($name);
$options = new CreateServiceOptions();
$options->setLocation('West US');
// Instead of setLocation, you can use setAffinityGroup to set an affinity group.

$result = $serviceManagementRestProxy->createHostedService($name, $label, $options);

Create a Deployment

To make a new deployment to Azure you must store the package file in a Microsoft Azure Blob Storage account under the same subscription as the hosted service to which the package is being uploaded. You can create a deployment package with the Microsoft Azure PowerShell cmdlets, or with the cspack commandline tool.

$hostedServiceName = "myhostedservice";
$deploymentName = "v1";
$slot = DeploymentSlot::PRODUCTION;
$packageUrl = "URL_for_.cspkg_file";
$configuration = file_get_contents('path_to_.cscfg_file');
$label = base64_encode($hostedServiceName);

$result = $serviceManagementRestProxy->createDeployment($hostedServiceName,
                         $deploymentName,
                         $slot,
                         $packageUrl,
                         $configuration,
                         $label);

$status = $serviceManagementRestProxy->getOperationStatus($result);
echo "Operation status: ".$status->getStatus()."<br />";

Media Services

Create new asset with file

To create an asset with a file you need to create an empty asset, create access policy with write permission, create a locator joining your asset and access policy, perform actual upload and generate file info.

$asset = new Asset(Asset::OPTIONS_NONE);
$asset = $restProxy->createAsset($asset);

$access = new AccessPolicy('[Some access policy name]');
$access->setDurationInMinutes([Munites AccessPolicy is valid]);
$access->setPermissions(AccessPolicy::PERMISSIONS_WRITE);
$access = $restProxy->createAccessPolicy($access);

$sasLocator = new Locator($asset,  $access, Locator::TYPE_SAS);
$sasLocator->setStartTime(new \DateTime('now -5 minutes'));
$sasLocator = $restProxy->createLocator($sasLocator);

$restProxy->uploadAssetFile($sasLocator, '[file name]', '[file content]');
$restProxy->createFileInfos($asset);

Encode asset

To perform media file encoding you will need input asset ($inputAsset) with a file in it (something like in previous chapter). Also you need to create an array of task data objects and a job data object. To create a task object use a media processor, task XML body and configuration name.

$mediaProcessor = $this->restProxy->getLatestMediaProcessor('[Media processor]');

$task = new Task('[Task XML body]', $mediaProcessor->getId(), TaskOptions::NONE);
$task->setConfiguration('[Configuration name]');

$restProxy->createJob(new Job(), array($inputAsset), array($task));

Get public URL to encoded asset

After you’ve uploaded a media file and encode it you can get a download URL for that file or a streaming URL for multiple bitrate files. Create a new access policy with read permission and link it with job output asset via locator.

$accessPolicy = new AccessPolicy('[Some access policy name]');
$accessPolicy->setDurationInMinutes([Munites AccessPolicy is valid]);
$accessPolicy->setPermissions(AccessPolicy::PERMISSIONS_READ);
$accessPolicy = $restProxy->createAccessPolicy($accessPolicy);

// Download URL
$sasLocator = new Locator($asset, $accessPolicy, Locator::TYPE_SAS);
$sasLocator->setStartTime(new \DateTime('now -5 minutes'));
$sasLocator = $restProxy->createLocator($sasLocator);

// Azure needs time to publish media
sleep(30);

$downloadUrl = $sasLocator->getBaseUri() . '/' . '[File name]' . $sasLocator->getContentAccessComponent()

// Streaming URL
$originLocator = new Locator($asset, $accessPolicy, Locator::TYPE_ON_DEMAND_ORIGIN);
$originLocator = $restProxy->createLocator($originLocator);

// Azure needs time to publish media
sleep(30);

$streamingUrl = $originLocator->getPath() . '[Manifest file name]' . "/manifest";

Manage media services entities

Media services CRUD operations are performed through media services rest proxy class. It has methods like “createAsset”, “createLocator”, “createJob” and etc. for entities creations.

To retrieve all entities list you may use methods “getAssetList”, “getAccessPolicyList”, “getLocatorList”, “getJobList” and etc. For getting single entity data use methods “getAsset”, “getJob”, “getTask” and etc. passing the entity identifier or entity data model object with non-empty identifier as a parameter.

Update entities with methods like “updateLocator”, “updateAsset”, “updateAssetFile” and etc. passing the entity data model object as a parameter. It is important to have valid entity identifier specified in data model object.

Erase entities with methods like “deleteAsset”, “deleteAccessPolicy”, “deleteJob” and etc. passing the entity identifier or entity data model object with non-empty identifier as a parameter.

Also you could get linked entities with methods “getAssetLocators”, “getAssetParentAssets”, “getAssetStorageAccount”, “getLocatorAccessPolicy”, “getJobTasks” and etc. passing the entity identifier or entity data model object with non-empty identifier as a parameter.

The complete list of all methods available you could find in IMediaServices interface.

For more examples please see the Microsoft Azure PHP Developer Center

Need Help?

Be sure to check out the Microsoft Azure Developer Forums on Stack Overflow if you have trouble with the provided code.

Contribute Code or Provide Feedback

If you would like to become an active contributor to this project please follow the instructions provided in Microsoft Azure Projects Contribution Guidelines.

To setup your development environment, follow the instructions in this wiki page.

If you encounter any bugs with the library please file an issue in the Issues section of the project.

Learn More

Microsoft Azure PHP Developer Center

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

azure-sdk-for-php's People

Contributors

antonba avatar azure-sdk avatar bradygaster avatar captn3m0 avatar cocteau666 avatar critch avatar devigned avatar jcookems avatar jeffwilcox avatar katmsft avatar kmvprograms avatar microsoft-github-policy-service[bot] avatar nickzhums avatar ogail avatar phansys avatar polkfarody avatar rdohms avatar rnrneverdies avatar roopalik avatar s-moon avatar sazpaimon avatar sergey-shandar avatar sergeyrazmyslov avatar svengerlach avatar tnimas avatar vladimirtsyshnatiy avatar weshaggard avatar xiaoningliu avatar yaqiyang avatar yuzorma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

azure-sdk-for-php's Issues

config doesn't work with storage emulator (URI property for configuration should be full uri)

Current implementation:
$config = Configuration::GetInstance();
$config->SetProperty(QueueConfiguration::ACCOUNT_NAME, 'test');
$config->SetProperty(QueueConfiguration::URI, 'queue.core.windows.net');

sdk implementation generates the uri by pre-pending the account name

Expected:
URI should be full url
$config->SetProperty(QueueConfiguration::URI, 'http://test.queue.core.windows.net');
as the current implementation won't work for

  1. storage emulator where the uri is http://127.0.0.1
  2. It should be consistent across languages.

Basically, the QueueRestProxy constructor should not append the account name to the uri.

Should not append unspecified keys to the URL

When I call listMessages('foo'), this URL is generated:

http://azuresdkdev.queue.core.windows.net/foo/messages?numofmessages=&visibilitytimeout=

The results are correct, but ideally the URL would be clean, without including empty keys (for numofmessages and visibilitytimeout)

incorrect Namespaces

Need to move src/WIndowsAzure/Core/Models folder to src/WIndowsAzure/Services/Core/Models
And also correct all queue namespaces to match the folder structure

Header category/package/author variables

  1. I'm not sure how PEAR surfaces things, but should we change the category to Windows Azure in case that's how folks search for all of our libraries?

  2. Is @Package the unit of distribution via PEAR? If so, we might want something a little less granular.

  3. I don't think we should have individual developer names for @author. Something like Microsoft Corporation [email protected] would be more appropriate.

  4. Should the link be to our github page rather than PEAR?
    16 + *
    17 + * @category Microsoft
    18 + * @Package PEAR2\WindowsAzure\Core\Exceptions
    19 + * @author Abdelrahman Elogeel [email protected]

    20 + * @copyright 2012 Microsoft Corporation
    21 + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0

    22 + * @link http://pear.php.net/package/azure-sdk-for-php

    23 + */

  5. we tell them what’s the name of our sdk and they just type this in cmd prompt: pear install azure-sdk
    [TG]: It's just that "Microsoft" is an incredibly broad @category when this SDK is only related to PHP and Windows Azure.
    [Ogail] The documentation annotations are not something related to PEAR, it’s something related to code. So when you use phpDocumenter to generate documentation, it’ll group all the packages under Microsoft name. The reason for choosing Microsoft is that Java’s namespace is Microsoft.WindowsAzure.* So We’ve the phrase Microsoft to group all packages. Again this in not related at all to how people will search for our package. PEAR distribution are specified in package.xml file.
    [TG]: We should work with the PM team on this, but even it's for grouping documentation we should still consider something more specific than just Microsoft.

Calling createQueue for an already created queue throws

When a createQueue is called with a new name, the server replies with:

HTTP/1.1 201 Created

When called a second time with the same name, the server replies with

HTTP/1.1 204 No Content

Neither is an error (both are < 400), just in the second case it is telling you that the queue already existed. This is a good thing, because potentially you could have two clients trying to create the same queue at the same time; as long as it exists in the end, all is good.

However, the current implementation of createQueue throws:

( ! ) Fatal error: Uncaught exception 'PEAR2\WindowsAzure\Core\ServiceException' with message ' in C:\wamp\www\php\PhpProject3\PEAR2\WindowsAzure\Core\HttpClient.php on line 243
( ! ) PEAR2\WindowsAzure\Core\ServiceException: Fail: Code: 204 Value: No Content details (if any): in C:\wamp\www\php\PhpProject3\PEAR2\WindowsAzure\Core\HttpClient.php on line 243
Call Stack
#   Time    Memory  Function    Location
1   0.0010  722128  {main}( )   ..\index.php:0
2   0.0209  1967632 foo->PollQueue( )   ..\index.php:114
3   0.0209  1967632 PEAR2\WindowsAzure\Services\Queue\QueueRestProxy->createQueue( )    ..\index.php:70
4   0.0218  2002624 PEAR2\WindowsAzure\Services\Queue\QueueRestProxy->send( )   ..\QueueRestProxy.php:277
5   0.0220  200719

The fix would be to add 204 to the list of expected return values..

Header category/package/author variables

  1. I'm not sure how PEAR surfaces things, but should we change the category to Windows Azure in case that's how folks search for all of our libraries?

  2. Is @Package the unit of distribution via PEAR? If so, we might want something a little less granular.

  3. I don't think we should have individual developer names for @author. Something like Microsoft Corporation [email protected] would be more appropriate.

  4. Should the link be to our github page rather than PEAR?
    16 + *
    17 + * @category Microsoft
    18 + * @Package PEAR2\WindowsAzure\Core\Exceptions
    19 + * @author Abdelrahman Elogeel [email protected]

    20 + * @copyright 2012 Microsoft Corporation
    21 + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0

    22 + * @link http://pear.php.net/package/azure-sdk-for-php

    23 + */

  5. we tell them what’s the name of our sdk and they just type this in cmd prompt: pear install azure-sdk
    [TG]: It's just that "Microsoft" is an incredibly broad @category when this SDK is only related to PHP and Windows Azure.
    [Ogail] The documentation annotations are not something related to PEAR, it’s something related to code. So when you use phpDocumenter to generate documentation, it’ll group all the packages under Microsoft name. The reason for choosing Microsoft is that Java’s namespace is Microsoft.WindowsAzure.* So We’ve the phrase Microsoft to group all packages. Again this in not related at all to how people will search for our package. PEAR distribution are specified in package.xml file.
    [TG]: We should work with the PM team on this, but even it's for grouping documentation we should still consider something more specific than just Microsoft.

Use Reflection to convert class member fields to XML

  1. It feels like these should maybe be part of some serialization interface. Don't do it yet, but I just wanted to suggest the idea to let it percolate. Then we could possibly use reflection to get all the properties of that type and automatically serialize them… I'm optimistic we'll be able to do something good to make serialization/deserialization easier here.

    111 + _/
    112 + public function toArray()
    113 + {
    114 + return array(
    115 + 'Logging' => $this->_logging->toArray(),
    116 + 'Metrics' => $this->metrics->toArray(),
    117 + );
    118 + }
    119 +
    120 + /
    *
    121 + * Converts this current object to XML representation.
    122 + *
    123 + * @return string
    124 + */
    125 + public function toXml()
    126 + {
    127 + return Utilities::serialize($this->toArray(), self::$xmLRootName);
    128 + }
    129 +}

Add namespace to test code

Currently PHPUnit fails to run the test code is organized in namespaces. Need to investigate what's the proper fix to that.

Create mock server for php sdk

We need to develop a mock server which will automate the regression check and also will be helpful in the automation of scenario tests.

Allow integer arguments for methods

Currently, several methods require string input when an integer value should be provided. For example, this code...

 $message_options = new CreateMessageOptions();
 $message_options->setVisibilityTimeoutInSeconds(60);

...produces this exception:

    PEAR2\WindowsAzure\Core\InvalidArgumentTypeException Object
    (
    [message:protected] => The provided variable should be of type: string

Changing 60 to "60" causes the method call to succeed.

This happens for methods on several classes. Having to provide a string input for an integer value is counter-intuitive.

Namespace for HttpClient does not match path

The HttpClient is in WindowsAzure\Core\HttpClient, but the namespace is PEAR2\WindowsAzure*Services*\Core. This breaks simple name-based autoloader, like this:

spl_autoload_register(
    function($class) {
        $cnBase  =   'pear2\\windowsazure\\';
        $cn = strtolower($class);
        if (strcmp(substr($cn, 0, strlen($cnBase)), $cnBase) == 0) {
            require __DIR__ . '\\' . $class . '.php';
        }

Making the change also requires WS/S/C/ServicesBuilder to add a "use PEAR2\WindowsAzure\Core\HttpClient;"

Enhance handling of appending url path

Currently you must provide the '/' along with the new portion. If Net2_URL::setUrl is used, the '/' is added automatically if the path is empty and then we can make append just takes the new portion

create configuration simpler alternative

While creating config, user has to specify bunch of setters.
$config = Configuration::GetInstance();
$config->SetProperty(QueueConfiguration::ACCOUNT_KEY, 'AhlzsbLRkjkwObubff3xrhB2yWJNh1EMptmcmxFJ6fvPTVX2PZXwrG2YtYWf5DPMVgNsteKStM5iBLlknYFVoA==');
$config->SetProperty(QueueConfiguration::ACCOUNT_NAME, 'aogailsvc');
$config->SetProperty(QueueConfiguration::URI, '.queue.core.windows.net');

I feel we can give an alternative to simplify this for the user. (something similar to ServiceBusConfiguration implemetation by louis in java)
$config = Configuration::GetInstance();
@Storageconfig.configureWithWrapAuthentication(config,"key","secret","name")

In my opinion this would be a p2.

All options need to support timeout

The queue supports an optional "timeout" URL parameter for all calls. It was mistakenly removed from the MSDN documentation, but you can take a look at the Java base class for Queue options. To verify that it is honored, you can specify a negative timeout for a request:

DELETE http://azuresdkdev.queue.core.windows.net/qa-146753-a1/messages/0a0fdf95-9818-4dfb-893f-f4ffcc536fb6?
    timeout=-1&popreceipt=AgAAAAEAAABDZAAANZjMArD8zAE%3D

And it the service will return:

HTTP/1.1 500 Operation could not be completed within the specified time.

targeting php 5.2 shows error for namespace and use keyword

Open the php project in ide and target it to use php 5.2
Actual: Shows errors for namepsace, use keywords.

As per the following spec we were planning to target php 5.2. Did this change?
http://sharepoint/sites/fxt/AzureSDK/_layouts/WordViewer.aspx?id=/sites/fxt/AzureSDK/PHP%20SDK/PHP%20Coding%20Guidelines.docx&Source=http%3A%2F%2Fsharepoint%2Fsites%2Ffxt%2FAzureSDK%2FSitePages%2FHome%2Easpx&DefaultItemOpen=1&DefaultItemOpen=1

As per the php documentation these keywords are supported in (PHP 5 >= 5.3.0)
http://www.php.net/manual/en/language.namespaces.importing.php

php sdk to throw ServiceException

instead of HTTP_Request2_ConnectionException (implementation detail exceptions)

This would help to hide the implementation details from the user.

Emulator doesn't work when running code from browser

With an environment variable EMULATED set to 1 and the storage emulator running, PHP scripts are still executing against live storage services when code is invoked from the browser. When the same code is invoked from the command line, PHP scripts are successfully executing against the local storage emulator.

Repo: Create environment variable EMULATED and set its value to 1. Start the storage emulator. Invoke this code from the browser:

$config = new Configuration();
$config->setProperty(QueueSettings::ACCOUNT_NAME, $storage_account_name);
$config->setProperty(QueueSettings::ACCOUNT_KEY, $storgae_account_key);
$config->setProperty(QueueSettings::URI, $storage_account_URI);

$queue_client = QueueService::create($config);

$queue_client->createQueue("myqueue", null);

This will create a queue (myqueue) in your live storage account. Execute the same code from the command line and it will create the queue in dev storage.

In order to have a complete development story, the queue should be created in dev storage when the code is invoked from the browser (since nearly all PHP apps are web apps and will be tested in a browser).

Jenkins env variables

Also we need to configure Jenkins env variables to be in project configuration like in node.js not in the machine global en variables.

Make build.xml cross platform

build.xml specifies the targets executable with *.bat extension. Need to discover how to eliminate the .bat part so the file can be used as cross platform/

Parameter validation for options would be helpful

I tried calling peekMessages('foo', 32), to get 32 messages. Instead I got a cryptic error message:

Fatal error: Call to a member function getNumberOfMessages() on a non-object in
C:\wamp\www\php\PhpProject3\PEAR2\WindowsAzure\Services\Queue\QueueRestProxy.php on line 455

peekMessages checks that the options is not null, but not that it is the correct type. It would be more helpful to get something like:

Fatal error: Uncaught exception 'InvalidArgumentException' with message 
'peekMessagesOptions needs to be a PeekMessagesOptions' in
C:\wamp\www\php\PhpProject3\PEAR2\WindowsAzure\Services\Queue\QueueRestProxy.php on line 454

which can come by adding:

    if (!($peekMessagesOptions instanceof PeekMessagesOptions)) {
        throw new \InvalidArgumentException("peekMessagesOptions needs to be a PeekMessagesOptions");
    }

sharing a autoload.php template with the user

For the e2e experience where user downloads the php sdk from git and starts using it, it would be nice to have a autoload.php template that customers can easily plugin to their existing apps.

Parameter validation needs to explain which parameter is invalid

We should take every reasonable step to ensure that the error experience is as helpful as possible, so people can get through the frustration as quickly as possible. (That why I marked it as P1). One area where we can improve is in the parameter validation. For example, I called deleteMessage with info I got from peeking messages

$queueService->deleteMessage('foo', $pm->getMessageId(), $pm->getPopReceipt());

I get the error:

Fatal error: Uncaught exception 'InvalidArgumentException' with message 'Value can't be NULL or empty.'

But which argument was invalid? It would be helpful to add the parameter name to the Validate methods, so the error could be

Fatal error: Uncaught exception 'InvalidArgumentException' with message 'argument "$popReceipt" can't be NULL or empty.'

Consider using fluent setters for classes that users set

Currently, it might take several lines to specify all the options for a complex operation. Consider this simple example:

    $opts = new PeekMessagesOptions();
    $opts->setNumberOfMessages(32);        
    $peekMsgsResult = $queueService->peekMessages($completedQueueName, $opts);

If our objects had fluent setters,

public function setNumberOfMessages($numberOfMessages)
{
    $this->_numberOfMessages = $numberOfMessages;
    return $this;
}

then we could write more compact code for options:

    $opts = (new PeekMessagesOptions())->setNumberOfMessages(32);        
    $peekMsgsResult = $this->queueService->peekMessages($completedQueueName, $opts);

or even

    $peekMsgsResult = $this->queueService->peekMessages($completedQueueName,
             (new PeekMessagesOptions())->setNumberOfMessages(32));

This is the approach Java has used.

Should not require trailing slash on QueueSettings::URI property

If I specify the seemingly reasonable

    $config->setProperty(QueueSettings::URI, 'http://azuresdkdev.queue.core.windows.net');

Then call createQueue('foo'), I get this error:

HTTP_Request2_ConnectionException: Unable to connect to tcp://azuresdkdev.queue.core.windows.netfoo:80.... 

After carefully going over the error message, I see that there is no slash between the URI I provided and the queue name. Having to manually correct this simple issue is a nuisance that we can easily work around.

One fix would be to just add the trailing slash if not present in the constructor for WindowsAzure/Core/Url:

$this->_url = new \Net_URL2($url . ($urlPath[strlen($urlpath)-1] == '/' ? '' : '/' ));

Decide and configure the project API documentation

Currently we use phpDocumenter but we need to replace it with phpdox. Further, Brain Swan suggested other tools to use. So we need to do the following:
a) Decide which documentation tool we'll use.
b) Configure build.xml to use this tool for generating the documentation.

Develop sample scenario calling REST API in PHP

Developing 2 sample scenarios one for storage (Queue) and other for service management to explain the usage of PHP SDK, Further after doing this we'll be able to decide what's HTTP library we are going to use and what XML library to use.

Creating queue uses XML\Parser.php, which violates Strict standards and calls Deprecated methods

I set up PHP in IIS, and set this in the PHP.INI:

error_reporting = E_ALL | E_STRICT

I have these PEAR packages installed:

Archive_Tar      1.3.9   stable
Console_Getopt   1.3.1   stable
HTTP_Request2    2.0.0   stable
Net_URL2         2.0.0   stable
PEAR             1.9.4   stable
Structures_Graph 1.0.4   stable
XML_Parser       1.3.4   stable
XML_Serializer   0.20.2  beta
XML_Util         1.2.1   stable

Then I have this code:

require 'autoload.php';
use PEAR2\WindowsAzure\Services\Core\Configuration;
use PEAR2\WindowsAzure\Services\Queue\QueueSettings;
use PEAR2\WindowsAzure\Services\Queue\QueueService;
$config = new Configuration();
$config->setProperty(QueueSettings::ACCOUNT_KEY, 'MY_KEY');
$config->setProperty(QueueSettings::ACCOUNT_NAME, 'MY_ACCOUNT');
$config->setProperty(QueueSettings::URI, 'queue.core.windows.net');
$queueService = QueueService::create($config);

Then, before the error saying that my account name is bad, I get these warnings:

  • PHP Strict standards: Redefining already defined constructor for class XML_Parser in C:\php\pear\XML\Parser.php on line 227
  • PHP Deprecated: Assigning the return value of new by reference is deprecated in C:\php\pear\XML\Parser.php on line 616
  • PHP Strict standards: Declaration of XML_Parser::raiseError() should be compatible with that of PEAR::raiseError() in C:\php\pear\XML\Parser.php on line 703

Stack trace:

{main}() C:\inetpub\wwwroot\php\PhpProject3\index.php:0
PEAR2\WindowsAzure\Services\Queue\QueueService::create() C:\inetpub\wwwroot\php\PhpProject3\index.php:20
PEAR2\WindowsAzure\Services\Core\Configuration->create() C:\inetpub\wwwroot\php\PhpProject3\PEAR2\WindowsAzure\Services\Queue\QueueService.php:52
PEAR2\WindowsAzure\Services\Core\ServicesBuilder::build() C:\inetpub\wwwroot\php\PhpProject3\PEAR2\WindowsAzure\Services\Core\Configuration.php:125
PEAR2\WindowsAzure\Services\Core\ServicesBuilder::_buildQueue() C:\inetpub\wwwroot\php\PhpProject3\PEAR2\WindowsAzure\Services\Core\ServicesBuilder.php:94
{closure}() C:\inetpub\wwwroot\php\PhpProject3\PEAR2\WindowsAzure\Services\Core\ServicesBuilder.php:0
require() C:\inetpub\wwwroot\php\PhpProject3\autoload.php:8
require_once() C:\inetpub\wwwroot\php\PhpProject3\PEAR2\WindowsAzure\Core\HttpClient.php:34

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.