Archive for admin

OpenX scalability & Performance using S3 and CloudFront

OpenX is one of the best ad servers I’ve used, but if you are tying to use it with large sites it will not work well: the speed of the OpenX servers will be very slow and unstable. The best solution that I have found is to use Amazon S3 + CloudFront CDN. But again, OpenX has its limitations and does not support this. You need to fix OpenX Code. There are some solutions on the web to use S3 rsync with NFS but again NFS not a scalable solution and slow if you have a lot of files.

Eight months ago I was working on very high traffic site that was using OpenX ads servers. To keep it working I amended the OpenX code to support S3 and CloudFront. I have shared the code below.

Create a new S3.php file under OpenX/lib; this is will be the main S3 class

S3.php code:

  1. < ?php
  2. /**
  3. * $Id$
  4. *
  5. * Copyright (c) 2007, Donovan Schonknecht.  All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. *
  10. * – Redistributions of source code must retain the above copyright notice,
  11. *   this list of conditions and the following disclaimer.
  12. * – Redistributions in binary form must reproduce the above copyright
  13. *   notice, this list of conditions and the following disclaimer in the
  14. *   documentation and/or other materials provided with the distribution.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  17. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  19. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  20. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  21. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  22. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  23. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  24. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  25. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  26. * POSSIBILITY OF SUCH DAMAGE.
  27. */
  28.  
  29. /**
  30. * Amazon S3 PHP class
  31. *
  32. * @link http://undesigned.org.za/2007/10/22/amazon-s3-php-class
  33. * @version 0.2.3
  34. */
  35. class S3 {
  36.  // ACL flags
  37.  const ACL_PRIVATE = 'private';
  38.  const ACL_PUBLIC_READ = 'public-read';
  39.  const ACL_PUBLIC_READ_WRITE = 'public-read-write';
  40.  
  41.  private static $__accessKey; // AWS Access key
  42.  private static $__secretKey; // AWS Secret key
  43.  
  44.  
  45.  /**
  46.  * Constructor, used if you're not calling the class statically
  47.  *
  48.  * @param string $accessKey Access key
  49.  * @param string $secretKey Secret key
  50.  * @return void
  51.  */
  52.  public function __construct($accessKey = null, $secretKey = null) {
  53.   if ($accessKey !== null && $secretKey !== null)
  54.    self::setAuth($accessKey, $secretKey);
  55.  }
  56.  
  57.  
  58.  /**
  59.  * Set access information
  60.  *
  61.  * @param string $accessKey Access key
  62.  * @param string $secretKey Secret key
  63.  * @return void
  64.  */
  65.  public static function setAuth($accessKey, $secretKey) {
  66.   self::$__accessKey = $accessKey;
  67.   self::$__secretKey = $secretKey;
  68.  }
  69.  
  70.  
  71.  /**
  72.  * Get a list of buckets
  73.  *
  74.  * @param boolean $detailed Returns detailed bucket list when true
  75.  * @return array | false
  76.  */
  77.  public static function listBuckets($detailed = false) {
  78.   $rest = new S3Request('GET', '', '');
  79.   $rest = $rest->getResponse();
  80.   if ($rest->error === false && $rest->code !== 200)
  81.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  82.   if ($rest->error !== false) {
  83.    trigger_error(sprintf("S3::listBuckets(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  84.    return false;
  85.   }
  86.   $results = array(); //var_dump($rest->body);
  87.   if (!isset($rest->body->Buckets)) return $results;
  88.  
  89.   if ($detailed) {
  90.    if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName))
  91.    $results['owner'] = array(
  92.     'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->ID
  93.    );
  94.    $results['buckets'] = array();
  95.    foreach ($rest->body->Buckets->Bucket as $b)
  96.     $results['buckets'][] = array(
  97.      'name' => (string)$b->Name, 'time' => strtotime((string)$b->CreationDate)
  98.     );
  99.   } else
  100.    foreach ($rest->body->Buckets->Bucket as $b) $results[] = (string)$b->Name;
  101.  
  102.   return $results;
  103.  }
  104.  
  105.  
  106.  /*
  107.  * Get contents for a bucket
  108.  *
  109.  * If maxKeys is null this method will loop through truncated result sets
  110.  *
  111.  * @param string $bucket Bucket name
  112.  * @param string $prefix Prefix
  113.  * @param string $marker Marker (last file listed)
  114.  * @param string $maxKeys Max keys (maximum number of keys to return)
  115.  * @return array | false
  116.  */
  117.  public static function getBucket($bucket, $prefix = null, $marker = null, $maxKeys = null) {
  118.   $rest = new S3Request('GET', $bucket, '');
  119.   if ($prefix !== null && $prefix !== '') $rest->setParameter('prefix', $prefix);
  120.   if ($marker !== null && $prefix !== '') $rest->setParameter('marker', $marker);
  121.   if ($maxKeys !== null && $prefix !== '') $rest->setParameter('max-keys', $maxKeys);
  122.   $response = $rest->getResponse();
  123.   if ($response->error === false && $response->code !== 200)
  124.    $response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status');
  125.   if ($response->error !== false) {
  126.    trigger_error(sprintf("S3::getBucket(): [%s] %s", $response->error['code'], $response->error['message']), E_USER_WARNING);
  127.    return false;
  128.   }
  129.  
  130.   $results = array();
  131.  
  132.   $lastMarker = null;
  133.   if (isset($response->body, $response->body->Contents))
  134.    foreach ($response->body->Contents as $c) {
  135.     $results[(string)$c->Key] = array(
  136.      'name' => (string)$c->Key,
  137.      'time' => strToTime((string)$c->LastModified),
  138.      'size' => (int)$c->Size,
  139.      'hash' => substr((string)$c->ETag, 1, -1)
  140.     );
  141.     $lastMarker = (string)$c->Key;
  142.     //$response->body->IsTruncated = 'true'; break;
  143.    }
  144.  
  145.  
  146.   if (isset($response->body->IsTruncated) &&
  147.   (string)$response->body->IsTruncated == 'false') return $results;
  148.  
  149.   // Loop through truncated results if maxKeys isn't specified
  150.   if ($maxKeys == null && $lastMarker !== null && (string)$response->body->IsTruncated == 'true')
  151.   do {
  152.    $rest = new S3Request('GET', $bucket, '');
  153.    if ($prefix !== null) $rest->setParameter('prefix', $prefix);
  154.    $rest->setParameter('marker', $lastMarker);
  155.  
  156.    if (($response = $rest->getResponse(true)) == false || $response->code !== 200) break;
  157.    if (isset($response->body, $response->body->Contents))
  158.     foreach ($response->body->Contents as $c) {
  159.      $results[(string)$c->Key] = array(
  160.       'name' => (string)$c->Key,
  161.       'time' => strToTime((string)$c->LastModified),
  162.       'size' => (int)$c->Size,
  163.       'hash' => substr((string)$c->ETag, 1, -1)
  164.      );
  165.      $lastMarker = (string)$c->Key;
  166.     }
  167.   } while ($response !== false && (string)$response->body->IsTruncated == 'true');
  168.  
  169.   return $results;
  170.  }
  171.  
  172.  
  173.  /**
  174.  * Put a bucket
  175.  *
  176.  * @param string $bucket Bucket name
  177.  * @param constant $acl ACL flag
  178.  * @return boolean
  179.  */
  180.  public function putBucket($bucket, $acl = self::ACL_PRIVATE) {
  181.   $rest = new S3Request('PUT', $bucket, '');
  182.   $rest->setAmzHeader('x-amz-acl', $acl);
  183.   $rest = $rest->getResponse();
  184.   if ($rest->error === false && $rest->code !== 200)
  185.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  186.   if ($rest->error !== false) {
  187.    trigger_error(sprintf("S3::putBucket({$bucket}): [%s] %s",
  188.    $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  189.    return false;
  190.   }
  191.   return true;
  192.  }
  193.  
  194.  
  195.  /**
  196.  * Delete an empty bucket
  197.  *
  198.  * @param string $bucket Bucket name
  199.  * @return boolean
  200.  */
  201.  public function deleteBucket($bucket = '') {
  202.   $rest = new S3Request('DELETE', $bucket);
  203.   $rest = $rest->getResponse();
  204.   if ($rest->error === false && $rest->code !== 204)
  205.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  206.   if ($rest->error !== false) {
  207.    trigger_error(sprintf("S3::deleteBucket({$bucket}): [%s] %s",
  208.    $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  209.    return false;
  210.   }
  211.   return true;
  212.  }
  213.  
  214.  
  215.  /**
  216.  * Create input info array for putObject()
  217.  *
  218.  * @param string $file Input file
  219.  * @param mixed $md5sum Use MD5 hash (supply a string if you want to use your own)
  220.  * @return array | false
  221.  */
  222.  public static function inputFile($file, $md5sum = true) {
  223.   if (!file_exists($file) || !is_file($file) || !is_readable($file)) {
  224.    trigger_error('S3::inputFile(): Unable to open input file: '.$file, E_USER_WARNING);
  225.    return false;
  226.   }
  227.   return array('file' => $file, 'size' => filesize($file),
  228.   'md5sum' => $md5sum !== false ? (is_string($md5sum) ? $md5sum :
  229.   base64_encode(md5_file($file, true))) : '');
  230.  }
  231.  
  232.  
  233.  /**
  234.  * Use a resource for input
  235.  *
  236.  * @param string $file Input file
  237.  * @param integer $bufferSize Input byte size
  238.  * @param string $md5sum MD5 hash to send (optional)
  239.  * @return array | false
  240.  */
  241.  public static function inputResource(&$resource, $bufferSize, $md5sum = '') {
  242.   if (!is_resource($resource) || $bufferSize < = 0) {
  243.    trigger_error('S3::inputResource(): Invalid resource or buffer size', E_USER_WARNING);
  244.    return false;
  245.   }
  246.   $input = array('size' => $bufferSize, 'md5sum' => $md5sum);
  247.   $input['fp'] =& $resource;
  248.   return $input;
  249.  }
  250.  
  251.  
  252.  /**
  253.  * Put an object
  254.  *
  255.  * @param mixed $input Input data
  256.  * @param string $bucket Bucket name
  257.  * @param string $uri Object URI
  258.  * @param constant $acl ACL constant
  259.  * @param array $metaHeaders Array of x-amz-meta-* headers
  260.  * @param string $contentType Content type
  261.  * @return boolean
  262.  */
  263.  public static function putObject($input, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) {
  264.   if ($input == false) return false;
  265.   $rest = new S3Request('PUT', $bucket, $uri);
  266.  
  267.   if (is_string($input)) $input = array(
  268.    'data' => $input, 'size' => strlen($input),
  269.    'md5sum' => base64_encode(md5($input, true))
  270.   );
  271.  
  272.   // Data
  273.   if (isset($input['fp']))
  274.    $rest->fp =& $input['fp'];
  275.   elseif (isset($input['file']))
  276.    $rest->fp = @fopen($input['file'], 'rb');
  277.   elseif (isset($input['data']))
  278.    $rest->data = $input['data'];
  279.  
  280.   // Content-Length (required)
  281.   if (isset($input['size']) && $input['size'] > 0)
  282.    $rest->size = $input['size'];
  283.   else {
  284.    if (isset($input['file']))
  285.     $rest->size = filesize($input['file']);
  286.    elseif (isset($input['data']))
  287.     $rest->size = strlen($input['data']);
  288.   }
  289.  
  290.   // Content-Type
  291.   if ($contentType !== null)
  292.    $input['type'] = $contentType;
  293.   elseif (!isset($input['type']) && isset($input['file']))
  294.    $input['type'] = self::__getMimeType($input['file']);
  295.   else
  296.    $input['type'] = 'application/octet-stream';
  297.  
  298.   // We need to post with the content-length and content-type, MD5 is optional
  299.   if ($rest->size > 0 && ($rest->fp !== false || $rest->data !== false)) {
  300.    $rest->setHeader('Content-Type', $input['type']);
  301.    if (isset($input['md5sum'])) $rest->setHeader('Content-MD5', $input['md5sum']);
  302.  
  303.    $rest->setAmzHeader('x-amz-acl', $acl);
  304.    foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
  305.    $rest->getResponse();
  306.   } else
  307.    $rest->response->error = array('code' => 0, 'message' => 'Missing input parameters');
  308.  
  309.   if ($rest->response->error === false && $rest->response->code !== 200)
  310.    $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
  311.   if ($rest->response->error !== false) {  
  312.    trigger_error(sprintf("S3::putObject(): [%s] %s", $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
  313.    return false;
  314.   }
  315.   return true;
  316.  }
  317.  
  318.  
  319.  /**
  320.  * Puts an object from a file (legacy function)
  321.  *
  322.  * @param string $file Input file path
  323.  * @param string $bucket Bucket name
  324.  * @param string $uri Object URI
  325.  * @param constant $acl ACL constant
  326.  * @param array $metaHeaders Array of x-amz-meta-* headers
  327.  * @param string $contentType Content type
  328.  * @return boolean
  329.  */
  330.  public static function putObjectFile($file, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = null) {
  331.   return self::putObject(S3::inputFile($file), $bucket, $uri, $acl, $metaHeaders, $contentType);
  332.  }
  333.  
  334.  
  335.  /**
  336.  * Put an object from a string (legacy function)
  337.  *
  338.  * @param string $string Input data
  339.  * @param string $bucket Bucket name
  340.  * @param string $uri Object URI
  341.  * @param constant $acl ACL constant
  342.  * @param array $metaHeaders Array of x-amz-meta-* headers
  343.  * @param string $contentType Content type
  344.  * @return boolean
  345.  */
  346.  public function putObjectString($string, $bucket, $uri, $acl = self::ACL_PRIVATE, $metaHeaders = array(), $contentType = 'text/plain') {
  347.   return self::putObject($string, $bucket, $uri, $acl, $metaHeaders, $contentType);
  348.  }
  349.  
  350.  
  351.  /**
  352.  * Get an object
  353.  *
  354.  * @param string $bucket Bucket name
  355.  * @param string $uri Object URI
  356.  * @param mixed &$saveTo Filename or resource to write to
  357.  * @return mixed
  358.  */
  359.  public static function getObject($bucket = '', $uri = '', $saveTo = false) {
  360.   $rest = new S3Request('GET', $bucket, $uri);
  361.   if ($saveTo !== false) {
  362.    if (is_resource($saveTo))
  363.     $rest->fp =& $saveTo;
  364.    else
  365.     if (($rest->fp = @fopen($saveTo, 'wb')) == false)
  366.     $rest->response->error = array('code' => 0, 'message' => 'Unable to open save file for writing: '.$saveTo);
  367.   }
  368.   if ($rest->response->error === false) $rest->getResponse();
  369.  
  370.   if ($rest->response->error === false && $rest->response->code !== 200)
  371.    $rest->response->error = array('code' => $rest->response->code, 'message' => 'Unexpected HTTP status');
  372.   if ($rest->response->error !== false) {
  373.    trigger_error(sprintf("S3::getObject({$bucket}, {$uri}): [%s] %s",
  374.    $rest->response->error['code'], $rest->response->error['message']), E_USER_WARNING);
  375.    return false;
  376.   }
  377.   $rest->file = realpath($saveTo);
  378.   return $rest->response;
  379.  }
  380.  
  381.  
  382.  /**
  383.  * Get object information
  384.  *
  385.  * @param string $bucket Bucket name
  386.  * @param string $uri Object URI
  387.  * @param boolean $returnInfo Return response information
  388.  * @return mixed | false
  389.  */
  390.  public static function getObjectInfo($bucket = '', $uri = '', $returnInfo = true) {
  391.   $rest = new S3Request('HEAD', $bucket, $uri);
  392.   $rest = $rest->getResponse();
  393.   if ($rest->error === false && ($rest->code !== 200 && $rest->code !== 404))
  394.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  395.   if ($rest->error !== false) {
  396.    trigger_error(sprintf("S3::getObjectInfo({$bucket}, {$uri}): [%s] %s",
  397.    $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  398.    return false;
  399.   }
  400.   return $rest->code == 200 ? $returnInfo ? $rest->headers : true : false;
  401.  }
  402.  
  403.  
  404.  /**
  405.  * Set logging for a bucket
  406.  *
  407.  * @param string $bucket Bucket name
  408.  * @param string $targetBucket Target bucket (where logs are stored)
  409.  * @param string $targetPrefix Log prefix (e,g; domain.com-)
  410.  * @return boolean
  411.  */
  412.  public static function setBucketLogging($bucket, $targetBucket, $targetPrefix) {
  413.   $dom = new DOMDocument;
  414.   $bucketLoggingStatus = $dom->createElement('BucketLoggingStatus');
  415.   $bucketLoggingStatus->setAttribute('xmlns', 'http://s3.amazonaws.com/doc/2006-03-01/');
  416.  
  417.   $loggingEnabled = $dom->createElement('LoggingEnabled');
  418.  
  419.   $loggingEnabled->appendChild($dom->createElement('TargetBucket', $targetBucket));
  420.   $loggingEnabled->appendChild($dom->createElement('TargetPrefix', $targetPrefix));
  421.  
  422.   // TODO: Add TargetGrants
  423.  
  424.   $bucketLoggingStatus->appendChild($loggingEnabled);
  425.   $dom->appendChild($bucketLoggingStatus);
  426.  
  427.   $rest = new S3Request('PUT', $bucket, '');
  428.   $rest->setParameter('logging', null);
  429.   $rest->data = $dom->saveXML();
  430.   $rest->size = strlen($rest->data);
  431.   $rest->setHeader('Content-Type', 'application/xml');
  432.   $rest = $rest->getResponse();
  433.   if ($rest->error === false && $rest->code !== 200)
  434.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  435.   if ($rest->error !== false) {
  436.    trigger_error(sprintf("S3::setBucketLogging({$bucket}, {$uri}): [%s] %s",
  437.    $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  438.    return false;
  439.   }
  440.   return true;
  441.  }
  442.  
  443.  
  444.  /**
  445.  * Get logging status for a bucket
  446.  *
  447.  * This will return false if logging is not enabled.
  448.  * Note: To enable logging, you also need to grant write access to the log group
  449.  *
  450.  * @param string $bucket Bucket name
  451.  * @return array | false
  452.  */
  453.  public static function getBucketLogging($bucket = '') {
  454.   $rest = new S3Request('GET', $bucket, '');
  455.   $rest->setParameter('logging', null);
  456.   $rest = $rest->getResponse();
  457.   if ($rest->error === false && $rest->code !== 200)
  458.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  459.   if ($rest->error !== false) {
  460.    trigger_error(sprintf("S3::getBucketLogging({$bucket}): [%s] %s",
  461.    $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  462.    return false;
  463.   }
  464.   if (!isset($rest->body->LoggingEnabled)) return false; // No logging
  465.   return array(
  466.    'targetBucket' => (string)$rest->body->LoggingEnabled->TargetBucket,
  467.    'targetPrefix' => (string)$rest->body->LoggingEnabled->TargetPrefix,
  468.   );
  469.  }
  470.  
  471.  
  472.  /**
  473.  * Set object or bucket Access Control Policy
  474.  *
  475.  * @param string $bucket Bucket name
  476.  * @param string $uri Object URI
  477.  * @param array $acp Access Control Policy Data (same as the data returned from getAccessControlPolicy)
  478.  * @return boolean
  479.  */
  480.  public static function setAccessControlPolicy($bucket, $uri = '', $acp = array()) {
  481.   $dom = new DOMDocument;
  482.   $dom->formatOutput = true;
  483.   $accessControlPolicy = $dom->createElement('AccessControlPolicy');
  484.   $accessControlList = $dom->createElement('AccessControlList');
  485.  
  486.   // It seems the owner has to be passed along too
  487.   $owner = $dom->createElement('Owner');
  488.   $owner->appendChild($dom->createElement('ID', $acp['owner']['id']));
  489.   $owner->appendChild($dom->createElement('DisplayName', $acp['owner']['name']));
  490.   $accessControlPolicy->appendChild($owner);
  491.  
  492.   foreach ($acp['acl'] as $g) {
  493.    $grant = $dom->createElement('Grant');
  494.    $grantee = $dom->createElement('Grantee');
  495.    $grantee->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
  496.    if (isset($g['id'])) { // CanonicalUser (DisplayName is omitted)
  497.     $grantee->setAttribute('xsi:type', 'CanonicalUser');
  498.     $grantee->appendChild($dom->createElement('ID', $g['id']));
  499.    } elseif (isset($g['email'])) { // AmazonCustomerByEmail
  500.     $grantee->setAttribute('xsi:type', 'AmazonCustomerByEmail');
  501.     $grantee->appendChild($dom->createElement('EmailAddress', $g['email']));
  502.    } elseif ($g['type'] == 'Group') { // Group
  503.     $grantee->setAttribute('xsi:type', 'Group');
  504.     $grantee->appendChild($dom->createElement('URI', $g['uri']));
  505.    }
  506.    $grant->appendChild($grantee);
  507.    $grant->appendChild($dom->createElement('Permission', $g['permission']));
  508.    $accessControlList->appendChild($grant);
  509.   }
  510.  
  511.   $accessControlPolicy->appendChild($accessControlList);
  512.   $dom->appendChild($accessControlPolicy);
  513.  
  514.   $rest = new S3Request('PUT', $bucket, '');
  515.   $rest->setParameter('acl', null);
  516.   $rest->data = $dom->saveXML();
  517.   $rest->size = strlen($rest->data);
  518.   $rest->setHeader('Content-Type', 'application/xml');
  519.   $rest = $rest->getResponse();
  520.   if ($rest->error === false && $rest->code !== 200)
  521.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  522.   if ($rest->error !== false) {
  523.    trigger_error(sprintf("S3::setAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
  524.    $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  525.    return false;
  526.   }
  527.   return true;
  528.  }
  529.  
  530.  
  531.  /**
  532.  * Get object or bucket Access Control Policy
  533.  *
  534.  * Currently this will trigger an error if there is no ACL on an object (will fix soon)
  535.  *
  536.  * @param string $bucket Bucket name
  537.  * @param string $uri Object URI
  538.  * @return mixed | false
  539.  */
  540.  public static function getAccessControlPolicy($bucket, $uri = '') {
  541.   $rest = new S3Request('GET', $bucket, $uri);
  542.   $rest->setParameter('acl', null);
  543.   $rest = $rest->getResponse();
  544.   if ($rest->error === false && $rest->code !== 200)
  545.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  546.   if ($rest->error !== false) {
  547.    trigger_error(sprintf("S3::getAccessControlPolicy({$bucket}, {$uri}): [%s] %s",
  548.    $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  549.    return false;
  550.   }
  551.  
  552.   $acp = array();
  553.   if (isset($rest->body->Owner, $rest->body->Owner->ID, $rest->body->Owner->DisplayName)) {
  554.    $acp['owner'] = array(
  555.     'id' => (string)$rest->body->Owner->ID, 'name' => (string)$rest->body->Owner->DisplayName
  556.    );
  557.   }
  558.   if (isset($rest->body->AccessControlList)) {
  559.    $acp['acl'] = array();
  560.    foreach ($rest->body->AccessControlList->Grant as $grant) {
  561.     foreach ($grant->Grantee as $grantee) {
  562.      if (isset($grantee->ID, $grantee->DisplayName)) // CanonicalUser
  563.       $acp['acl'][] = array(
  564.        'type' => 'CanonicalUser',
  565.        'id' => (string)$grantee->ID,
  566.        'name' => (string)$grantee->DisplayName,
  567.        'permission' => (string)$grant->Permission
  568.       );
  569.      elseif (isset($grantee->EmailAddress)) // AmazonCustomerByEmail
  570.       $acp['acl'][] = array(
  571.        'type' => 'AmazonCustomerByEmail',
  572.        'email' => (string)$grantee->EmailAddress,
  573.        'permission' => (string)$grant->Permission
  574.       );
  575.      elseif (isset($grantee->URI)) // Group
  576.       $acp['acl'][] = array(
  577.        'type' => 'Group',
  578.        'uri' => (string)$grantee->URI,
  579.        'permission' => (string)$grant->Permission
  580.       );
  581.      else continue;
  582.     }
  583.    }
  584.   }
  585.   return $acp;
  586.  }
  587.  
  588.  
  589.  /**
  590.  * Delete an object
  591.  *
  592.  * @param string $bucket Bucket name
  593.  * @param string $uri Object URI
  594.  * @return mixed
  595.  */
  596.  public static function deleteObject($bucket = '', $uri = '') {
  597.   $rest = new S3Request('DELETE', $bucket, $uri);
  598.   $rest = $rest->getResponse();
  599.   if ($rest->error === false && $rest->code !== 204)
  600.    $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
  601.   if ($rest->error !== false) {
  602.    trigger_error(sprintf("S3::deleteObject(): [%s] %s", $rest->error['code'], $rest->error['message']), E_USER_WARNING);
  603.    return false;
  604.   }
  605.   return true;
  606.  }
  607.  
  608.  
  609.  /**
  610.  * Get MIME type for file
  611.  *
  612.  * @internal Used to get mime types
  613.  * @param string &$file File path
  614.  * @return string
  615.  */
  616.  public static function __getMimeType(&$file) {
  617.   $type = false;
  618.   // Fileinfo documentation says fileinfo_open() will use the
  619.   // MAGIC env var for the magic file
  620.   if (extension_loaded('fileinfo') && isset($_ENV['MAGIC']) &&
  621.   ($finfo = finfo_open(FILEINFO_MIME, $_ENV['MAGIC'])) !== false) {
  622.    if (($type = finfo_file($finfo, $file)) !== false) {
  623.     // Remove the charset and grab the last content-type
  624.     $type = explode(' ', str_replace('; charset=', ';charset=', $type));
  625.     $type = array_pop($type);
  626.     $type = explode(';', $type);
  627.     $type = array_shift($type);
  628.    }
  629.    finfo_close($finfo);
  630.  
  631.   // If anyone is still using mime_content_type()
  632.   } elseif (function_exists('mime_content_type'))
  633.    $type = mime_content_type($file);
  634.  
  635.   if ($type !== false && strlen($type) > 0) return $type;
  636.  
  637.   // Otherwise do it the old fashioned way
  638.   static $exts = array(
  639.    'jpg' => 'image/jpeg', 'gif' => 'image/gif', 'png' => 'image/png',
  640.    'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'ico' => 'image/x-icon',
  641.    'swf' => 'application/x-shockwave-flash', 'pdf' => 'application/pdf',
  642.    'zip' => 'application/zip', 'gz' => 'application/x-gzip',
  643.    'tar' => 'application/x-tar', 'bz' => 'application/x-bzip',
  644.    'bz2' => 'application/x-bzip2', 'txt' => 'text/plain',
  645.    'asc' => 'text/plain', 'htm' => 'text/html', 'html' => 'text/html',
  646.    'xml' => 'text/xml', 'xsl' => 'application/xsl+xml',
  647.    'ogg' => 'application/ogg', 'mp3' => 'audio/mpeg', 'wav' => 'audio/x-wav',
  648.    'avi' => 'video/x-msvideo', 'mpg' => 'video/mpeg', 'mpeg' => 'video/mpeg',
  649.    'mov' => 'video/quicktime', 'flv' => 'video/x-flv', 'php' => 'text/x-php'
  650.   );
  651.   $ext = strToLower(pathInfo($file, PATHINFO_EXTENSION));
  652.   return isset($exts[$ext]) ? $exts[$ext] : 'application/octet-stream';
  653.  }
  654.  
  655.  
  656.  /**
  657.  * Generate the auth string: "AWS AccessKey:Signature"
  658.  *
  659.  * This uses the hash extension if loaded
  660.  *
  661.  * @internal Signs the request
  662.  * @param string $string String to sign
  663.  * @return string
  664.  */
  665.  public static function __getSignature($string) {
  666.   return 'AWS '.self::$__accessKey.':'.base64_encode(extension_loaded('hash') ?
  667.   hash_hmac('sha1', $string, self::$__secretKey, true) : pack('H*', sha1(
  668.   (str_pad(self::$__secretKey, 64, chr(0×00)) ^ (str_repeat(chr(0x5c), 64))) .
  669.   pack('H*', sha1((str_pad(self::$__secretKey, 64, chr(0×00)) ^
  670.   (str_repeat(chr(0×36), 64))) . $string)))));
  671.  }
  672.  
  673.  
  674. }
  675.  
  676. final class S3Request {
  677.  private $verb, $bucket, $uri, $resource = '', $parameters = array(),
  678.  $amzHeaders = array(), $headers = array(
  679.   'Host' => '', 'Date' => '', 'Content-MD5' => '', 'Content-Type' => ''
  680.  );
  681.  public $fp = false, $size = 0, $data = false, $response;
  682.  
  683.  
  684.  /**
  685.  * Constructor
  686.  *
  687.  * @param string $verb Verb
  688.  * @param string $bucket Bucket name
  689.  * @param string $uri Object URI
  690.  * @return mixed
  691.  */
  692.  function __construct($verb, $bucket = '', $uri = '') {
  693.   $this->verb = $verb;
  694.   $this->bucket = strtolower($bucket);
  695.   $this->uri = $uri !== '' ? '/'.$uri : '/';
  696.  
  697.   if ($this->bucket !== '') {
  698.    $this->bucket = explode('/', $this->bucket);
  699.    $this->resource = '/'.$this->bucket[0].$this->uri;
  700.    $this->headers['Host'] = $this->bucket[0].'.s3.amazonaws.com';
  701.    $this->bucket = implode('/', $this->bucket);
  702.   } else {
  703.    $this->headers['Host'] = 's3.amazonaws.com';
  704.    if (strlen($this->uri) > 1)
  705.     $this->resource = '/'.$this->bucket.$this->uri;
  706.    else $this->resource = $this->uri;
  707.   }
  708.   $this->headers['Date'] = gmdate('D, d M Y H:i:s T');
  709.  
  710.   $this->response = new STDClass;
  711.   $this->response->error = false;
  712.  }
  713.  
  714.  
  715.  /**
  716.  * Set request parameter
  717.  *
  718.  * @param string $key Key
  719.  * @param string $value Value
  720.  * @return void
  721.  */
  722.  public function setParameter($key, $value) {
  723.   $this->parameters[$key] = $value;
  724.  }
  725.  
  726.  
  727.  /**
  728.  * Set request header
  729.  *
  730.  * @param string $key Key
  731.  * @param string $value Value
  732.  * @return void
  733.  */
  734.  public function setHeader($key, $value) {
  735.   $this->headers[$key] = $value;
  736.  }
  737.  
  738.  
  739.  /**
  740.  * Set x-amz-meta-* header
  741.  *
  742.  * @param string $key Key
  743.  * @param string $value Value
  744.  * @return void
  745.  */
  746.  public function setAmzHeader($key, $value) {
  747.   $this->amzHeaders[$key] = $value;
  748.  }
  749.  
  750.  
  751.  /**
  752.  * Get the S3 response
  753.  *
  754.  * @return object | false
  755.  */
  756.  public function getResponse() {
  757.   $query = '';
  758.   if (sizeof($this->parameters) > 0) {
  759.    $query = substr($this->uri, -1) !== '?' ? '?' : '&';
  760.    foreach ($this->parameters as $var => $value)
  761.     if ($value == null || $value == '') $query .= $var.'&';
  762.     else $query .= $var.'='.$value.'&';
  763.    $query = substr($query, 0, -1);
  764.    $this->uri .= $query;
  765.    if (isset($this->parameters['acl']) || !isset($this->parameters['logging']))
  766.     $this->resource .= $query;
  767.   }
  768.   $url = (extension_loaded('openssl')?'https://':'http://').$this->headers['Host'].$this->uri;
  769.   //var_dump($this->bucket, $this->uri, $this->resource, $url);
  770.  
  771.   // Basic setup
  772.   $curl = curl_init();
  773.   curl_setopt($curl, CURLOPT_USERAGENT, 'S3/php');
  774.   curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
  775.   curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
  776.   curl_setopt($curl, CURLOPT_URL, $url);
  777.  
  778.   // Headers
  779.   $headers = array(); $amz = array();
  780.   foreach ($this->amzHeaders as $header => $value)
  781.    if (strlen($value) > 0) $headers[] = $header.': '.$value;
  782.   foreach ($this->headers as $header => $value)
  783.    if (strlen($value) > 0) $headers[] = $header.': '.$value;
  784.   foreach ($this->amzHeaders as $header => $value)
  785.    if (strlen($value) > 0) $amz[] = strToLower($header).':'.$value;
  786.   $amz = (sizeof($amz) > 0) ? "\n".implode("\n", $amz) : '';
  787.  
  788.   // Authorization string
  789.   $headers[] = 'Authorization: ' . S3::__getSignature(
  790.    $this->verb."\n".
  791.    $this->headers['Content-MD5']."\n".
  792.    $this->headers['Content-Type']."\n".
  793.    $this->headers['Date'].$amz."\n".$this->resource
  794.   );
  795.  
  796.   curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  797.   curl_setopt($curl, CURLOPT_HEADER, false);
  798.   curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
  799.   curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
  800.   curl_setopt($curl, CURLOPT_HEADERFUNCTION, array(&$this, '__responseHeaderCallback'));
  801.  
  802.   // Request types
  803.   switch ($this->verb) {
  804.    case 'GET': break;
  805.    case 'PUT':
  806.     if ($this->fp !== false) {
  807.      curl_setopt($curl, CURLOPT_PUT, true);
  808.      curl_setopt($curl, CURLOPT_INFILE, $this->fp);
  809.      if ($this->size > 0)
  810.       curl_setopt($curl, CURLOPT_INFILESIZE, $this->size);
  811.     } elseif ($this->data !== false) {
  812.      curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
  813.      curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
  814.      if ($this->size > 0)
  815.       curl_setopt($curl, CURLOPT_BUFFERSIZE, $this->size);
  816.     } else
  817.      curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
  818.    break;
  819.    case 'HEAD':
  820.     curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
  821.     curl_setopt($curl, CURLOPT_NOBODY, true);
  822.    break;
  823.    case 'DELETE':
  824.     curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
  825.    break;
  826.    default: break;
  827.   }
  828.  
  829.   // Execute, grab errors
  830.   if (curl_exec($curl))
  831.    $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  832.   else
  833.    $this->response->error = array(
  834.     'code' => curl_errno($curl),
  835.     'message' => curl_error($curl),
  836.     'resource' => $this->resource
  837.    );
  838.  
  839.   @curl_close($curl);
  840.  
  841.   // Parse body into XML
  842.   if ($this->response->error === false && isset($this->response->headers['type']) &&
  843.   $this->response->headers['type'] == 'application/xml' && isset($this->response->body)) {
  844.    $this->response->body = simplexml_load_string($this->response->body);
  845.  
  846.    // Grab S3 errors
  847.    if (!in_array($this->response->code, array(200, 204)) &&
  848.    isset($this->response->body->Code, $this->response->body->Message)) {
  849.     $this->response->error = array(
  850.      'code' => (string)$this->response->body->Code,
  851.      'message' => (string)$this->response->body->Message
  852.     );
  853.     if (isset($this->response->body->Resource))
  854.      $this->response->error['resource'] = (string)$this->response->body->Resource;
  855.     unset($this->response->body);
  856.    }
  857.   }
  858.  
  859.   // Clean up file resources
  860.   if ($this->fp !== false && is_resource($this->fp)) fclose($this->fp);
  861.  
  862.   return $this->response;
  863.  }
  864.  
  865.  
  866.  /**
  867.  * CURL write callback
  868.  *
  869.  * @param resource &$curl CURL resource
  870.  * @param string &$data Data
  871.  * @return integer
  872.  */
  873.  private function __responseWriteCallback(&$curl, &$data) {
  874.   if ($this->response->code == 200 && $this->fp !== false)
  875.    return fwrite($this->fp, $data);
  876.   else
  877.    $this->response->body .= $data;
  878.   return strlen($data);
  879.  }
  880.  
  881.  
  882.  /**
  883.  * CURL header callback
  884.  *
  885.  * @param resource &$curl CURL resource
  886.  * @param string &$data Data
  887.  * @return integer
  888.  */
  889.  private function __responseHeaderCallback(&$curl, &$data) {
  890.   if (($strlen = strlen($data)) < = 2) return $strlen;
  891.   if (substr($data, 0, 4) == 'HTTP')
  892.    $this->response->code = (int)substr($data, 9, 3);
  893.   else {
  894.    list($header, $value) = explode(': ', trim($data));
  895.    if ($header == 'Last-Modified')
  896.     $this->response->headers['time'] = strtotime($value);
  897.    elseif ($header == 'Content-Length')
  898.     $this->response->headers['size'] = (int)$value;
  899.    elseif ($header == 'Content-Type')
  900.     $this->response->headers['type'] = $value;
  901.    elseif ($header == 'ETag')
  902.     $this->response->headers['hash'] = substr($value, 1, -1);
  903.    elseif (preg_match('/^x-amz-meta-.*$/', $header))
  904.     $this->response->headers[$header] = is_numeric($value) ? (int)$value : $value;
  905.   }
  906.   return $strlen;
  907.  }
  908.  
  909. }
  910. ?>

Got to OpenX/www/admin/lib-storage.inc.php

Line 30 add

  1. require_once MAX_PATH . '/lib/S3.php';

Replace the phpAds_ImageStore function with below,with this all images will be upload to S3 and don’t forget to setup your awsAccessKey

  1. function phpAds_ImageStore($type, $name, $buffer, $overwrite = false)
  2. {
  3.  $aConf = $GLOBALS['_MAX']['CONF'];
  4.  $pref = $GLOBALS['_MAX']['PREF'];
  5.  // Make name web friendly
  6.  $name = basename($name);
  7.  $name = strtolower($name);
  8.  $name = str_replace(" ", "_", $name);
  9.  $name = str_replace("'", "", $name);
  10.  $extension = substr($name, strrpos($name, "."));
  11.  if ($type == 'web') {
  12.   $filename = phpAds_LocalUniqueName($buffer, $extension);
  13.   // ***********************************************************************************************************************************
  14.   if (!defined('awsAccessKey')) define('awsAccessKey', 'Your Key');
  15.   if (!defined('awsSecretKey')) define('awsSecretKey', 'Your Key');
  16.   $s3 = new S3(awsAccessKey, awsSecretKey);
  17.  
  18.   //$s3->putBucket("ads.logta.com", S3::ACL_PUBLIC_READ);
  19.   if ($s3->putObjectFile($buffer, "ads.logta.com", $filename, S3::ACL_PUBLIC_READ)) {
  20.    $stored_url = $filename;
  21.   }else{
  22.     $stored_url = "wrong24";
  23.   }
  24.  
  25.   // ************************************************************************************************************************************
  26.   /*
  27.    $filename = phpAds_LocalUniqueName($buffer, $extension);
  28.    if ($aConf['store']['mode'] == 'ftp') {
  29.    // FTP mode
  30.    $server = array();
  31.    $server['host'] = $aConf['store']['ftpHost'];
  32.    $server['path'] = $aConf['store']['ftpPath'];
  33.    if (($server['path'] != "") && (substr($server['path'], 0, 1) == "/")) {
  34.        $server['path'] = substr($server['path'], 1);
  35.    }
  36.    $server['user'] = $aConf['store']['ftpUsername'];
  37.    $server['pass'] = $aConf['store']['ftpPassword'];
  38.    $server['passiv'] = !empty( $aConf['store']['ftpPassive'] );
  39.             $stored_url = phpAds_FTPStore($server, $filename, $buffer, true);
  40.   } else {
  41.    // Local mode, get the unique filename
  42.    $filename = phpAds_LocalUniqueName($buffer, $extension);
  43.    // Doe the file exist already?
  44.             if (@file_exists($aConf['store']['webDir']."/".$filename) == false) {
  45.        // Write the file
  46.        if ($fp = @fopen($aConf['store']['webDir']."/".$filename, 'wb')) {
  47.         @fwrite($fp, $buffer);
  48.         @fclose($fp);
  49.         $stored_url = $filename;
  50.        }
  51.             } else {
  52.                 $stored_url = $filename;
  53.             }
  54.   }*/
  55.  }

Now go to your setting file Openx/var/ads.logta.com.conf.php

Find [webpath] and add your CloudFront or CDN domain like in images parameters

  1. admin="Your website name/www/admin"
  2. delivery="Your website name/www/delivery"
  3. deliverySSL="Your website name/www/delivery"
  4. images="openx_CDN_1.cloudfront.net,openx_CDN_2.cloudfront.net,openx_CDN__3.cloudfront.net"
  5. imagesSSL="openx_CDN_1.cloudfront.net,openx_CDN_2.cloudfront.net,openx_CDN__3.cloudfront.net"

Next step we need to fix the Banners loding path so.. go to Openx/www/admin/account-settings-banner-delivery.php And update the code with below

  1. < ?php
  2.  
  3. /*
  4. +—————————————————————————+
  5. | OpenX v2.8                                                                |
  6. | ==========                                                                |
  7. |                                                                           |
  8. | Copyright (c) 2003-2009 OpenX Limited                                     |
  9. | For contact details, see: http://www.openx.org/                           |
  10. |                                                                           |
  11. | This program is free software; you can redistribute it and/or modify      |
  12. | it under the terms of the GNU General Public License as published by      |
  13. | the Free Software Foundation; either version 2 of the License, or         |
  14. | (at your option) any later version.                                       |
  15. |                                                                           |
  16. | This program is distributed in the hope that it will be useful,           |
  17. | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
  18. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
  19. | GNU General Public License for more details.                              |
  20. |                                                                           |
  21. | You should have received a copy of the GNU General Public License         |
  22. | along with this program; if not, write to the Free Software               |
  23. | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA |
  24. +—————————————————————————+
  25. $Id: account-settings-banner-delivery.php 62345 2010-09-14 21:16:38Z chris.nutting $
  26. */
  27.  
  28. // Require the initialisation file
  29. require_once '../../init.php';
  30.  
  31. // Required files
  32. require_once MAX_PATH . '/lib/OA/Admin/Option.php';
  33. require_once MAX_PATH . '/lib/OA/Admin/Settings.php';
  34.  
  35. require_once MAX_PATH . '/lib/max/Plugin/Translation.php';
  36. require_once MAX_PATH . '/lib/OX/Plugin/Component.php';
  37. require_once MAX_PATH . '/www/admin/config.php';
  38.  
  39.  
  40. // Security check
  41. OA_Permission::enforceAccount(OA_ACCOUNT_ADMIN);
  42.  
  43. // Load translation class
  44. $oTranslation = new OX_Translation();
  45.  
  46. // Create a new option object for displaying the setting's page's HTML form
  47. $oOptions = new OA_Admin_Option('settings');
  48. $prefSection = "banner-delivery";
  49.  
  50. // This page depends on deliveryCacheStore plugins, so get the required
  51. // information about all such plugins installed in this installation
  52. $aDeliveryCacheStores = OX_Component::getComponents('deliveryCacheStore', null, false);
  53.  
  54. // This page depends on 3rdPartyServers plugins, so get the required
  55. // information about all such plugins installed in this installation]
  56. $a3rdPartyServers = &OX_Component::getComponents('3rdPartyServers');
  57.  
  58. // Prepare an array for storing error messages
  59. $aErrormessage = array();
  60.  
  61. // If the settings page is a submission, deal with the form data
  62. if (isset($_POST['submitok']) && $_POST['submitok'] == 'true') {
  63.     // Prepare an array of the HTML elements to process, and the
  64.     // location to save the values in the settings configuration
  65.     // file
  66.     $aElements = array();
  67.     // Banner Delivery Cache Settings
  68.     $aElements += array(
  69.         'delivery_cacheExpire' => array('delivery' => 'cacheExpire'),
  70.         'delivery_cacheStorePlugin' => array('delivery' => 'cacheStorePlugin')
  71.     );
  72.  
  73.     // Banner Delivery Settings
  74.     $aElements += array(
  75.         'delivery_acls' => array(
  76.             'delivery' => 'acls',
  77.             'bool'     => true
  78.         ),
  79.         'delivery_aclsDirectSelection' => array(
  80.             'delivery' => 'acls',
  81.             'bool'     => true
  82.         ),
  83.         'delivery_obfuscate' => array(
  84.             'delivery' => 'obfuscate',
  85.             'bool'     => true
  86.         ),
  87.         'delivery_execPhp' => array(
  88.             'delivery' => 'execPhp',
  89.             'bool'     => true
  90.         ),
  91.         'delivery_ctDelimiter' => array('delivery' => 'ctDelimiter'),
  92.         'defaultBanner_imageUrl' => array('defaultBanner' => 'imageUrl')
  93.     );
  94.     // Invocation Defaults
  95.     $aElements += array(
  96.         'delivery_clicktracking' => array('delivery' => 'clicktracking')
  97.     );
  98.     // P3P Privacy Policies
  99.     $aElements += array(
  100.         'p3p_policies' => array(
  101.             'p3p'  => 'policies',
  102.             'bool' => true
  103.         ),
  104.         'p3p_compactPolicy'  => array('p3p' => 'compactPolicy'),
  105.         'p3p_policyLocation' => array('p3p' => 'policyLocation')
  106.     );
  107.     // OpenX Server Access Paths
  108.     $aElements += array(
  109.         'webpath_admin' => array(
  110.             'webpath'      => 'admin',
  111.             'preg_match'   => '#/$#',
  112.             'preg_replace' => ''
  113.         ),
  114.         'webpath_delivery' => array(
  115.             'webpath'      => 'delivery',
  116.             'preg_match'   => '#/$#',
  117.             'preg_replace' => ''
  118.         ),
  119.         'webpath_deliverySSL' => array(
  120.             'webpath'      => 'deliverySSL',
  121.             'preg_match'   => '#/$#',
  122.             'preg_replace' => ''
  123.         ),
  124.         'webpath_images' => array(
  125.             'webpath'      => 'images',
  126.             'preg_match'   => '#/$#',
  127.             'preg_replace' => ''
  128.         ),
  129.         'webpath_imagesSSL' => array(
  130.             'webpath'      => 'imagesSSL',
  131.             'preg_match'   => '#/$#',
  132.             'preg_replace' => ''
  133.         )
  134.     );
  135.     // Delivery File Names
  136.     $aElements += array(
  137.         'file_click'           => array('file' => 'click'),
  138.         'file_conversionvars'  => array('file' => 'conversionvars'),
  139.         'file_content'         => array('file' => 'content'),
  140.         'file_conversion'      => array('file' => 'conversion'),
  141.         'file_conversionjs'    => array('file' => 'conversionjs'),
  142.         'file_frame'           => array('file' => 'frame'),
  143.         'file_image'           => array('file' => 'image'),
  144.         'file_js'              => array('file' => 'js'),
  145.         'file_layer'           => array('file' => 'layer'),
  146.         'file_log'             => array('file' => 'log'),
  147.         'file_popup'           => array('file' => 'popup'),
  148.         'file_view'            => array('file' => 'view'),
  149.         'file_xmlrpc'          => array('file' => 'xmlrpc'),
  150.         'file_local'           => array('file' => 'local'),
  151.         'file_frontcontroller' => array('file' => 'frontcontroller'),
  152.         'file_flash'           => array('file' => 'flash')
  153.     );
  154.     // Test the suitability of the cache store type, if required
  155.     MAX_commonRegisterGlobalsArray(array('delivery_cacheStorePlugin'));
  156.     if (isset($delivery_cacheStorePlugin)) {
  157.         // Check for problems in selected delivery store plugin
  158.         $oDeliveryCacheStore = &OX_Component::factoryByComponentIdentifier($delivery_cacheStorePlugin);
  159.         $result = $oDeliveryCacheStore->getStatus();
  160.         if ($result !== true) {
  161.             $aErrormessage[1][] = $oTranslation->translate(
  162.                 'ErrorInCacheStorePlugin',
  163.                 array($oDeliveryCacheStore->getName())
  164.             );
  165.             foreach ($result as $error) {
  166.                 $aErrormessage[1][] = " – ".$error;
  167.             }
  168.         }
  169.     }
  170.     if (empty($aErrormessage)) {
  171.         // Create a new settings object, and save the settings!
  172.         $oSettings = new OA_Admin_Settings();
  173.         $result = $oSettings->processSettingsFromForm($aElements);
  174.         if ($result) {
  175.             // Queue confirmation message
  176.             $setPref = $oOptions->getSettingsPreferences($prefSection);
  177.             $title = $setPref[$prefSection]['name'];
  178.             $translation = new OX_Translation ();
  179.             $translated_message = $translation->translate($GLOBALS['strXSettingsHaveBeenUpdated'],
  180.                 array(htmlspecialchars($title)));
  181.             OA_Admin_UI::queueMessage($translated_message, 'local', 'confirm', 0);
  182.  
  183.             // The settings configuration file was written correctly,
  184.             // go to the "next" settings page from here
  185.             OX_Admin_Redirect::redirect(basename($_SERVER['SCRIPT_NAME']));
  186.         }
  187.         // Could not write the settings configuration file, store this
  188.         // error message and continue
  189.         $aErrormessage[0][] = $strUnableToWriteConfig;
  190.  
  191.     }
  192. }
  193.  
  194. // Set the correct section of the settings pages and display the drop-down menu
  195. $setPref = $oOptions->getSettingsPreferences($prefSection);
  196. $title = $setPref[$prefSection]['name'];
  197.  
  198. // Display the settings page's header and sections
  199. $oHeaderModel = new OA_Admin_UI_Model_PageHeaderModel($title);
  200. phpAds_PageHeader('account-settings-index', $oHeaderModel);
  201.  
  202. // This page depends on deliveryCacheStore plugins, so use the plugin
  203. // information from earlier to generate the elements for the plugins
  204. // which is required in the next section
  205.  
  206. $aCacheStoresSelect = array();
  207. foreach ($aDeliveryCacheStores as $pluginKey => $oCacheStore) {
  208.     $aCacheStoresSelect[$oCacheStore->getComponentIdentifier()] = $oCacheStore->getName();
  209. }
  210.  
  211. $aDeliveryCacheSettings = array (
  212.     array (
  213.             'type'    => 'text',
  214.             'name'    => 'delivery_cacheExpire',
  215.             'text'    => $strDeliveryCacheLimit,
  216.             'check'   => 'wholeNumber'
  217.         ),
  218.     array (
  219.             'type'    => 'break'
  220.         ),
  221.     array (
  222.             'type'  => 'select',
  223.             'name'  => 'delivery_cacheStorePlugin',
  224.             'text'  => $strDeliveryCacheStore,
  225.             'items' => $aCacheStoresSelect
  226.         )
  227. );
  228.  
  229. // This page depends on 3rdPartyServers plugins, so use the plugin
  230. // information from earlier to generate the elements for the plugins
  231. // which is required in the next section
  232. $availableOutputAdServerNames = array();
  233. foreach ($a3rdPartyServers as $pluginKey => $outputAdServer) {
  234.     if ($outputAdServer->hasOutputMacros) {
  235.         $availableOutputAdServers[$pluginKey] = $outputAdServer;
  236.         $availableOutputAdServerNames[$pluginKey] = $outputAdServer->getName();
  237.     }
  238. }
  239. asort($availableOutputAdServerNames);
  240. $availableOutputAdServerNames = $availableOutputAdServerNames = array(
  241.     0 => $GLOBALS['strNo'],
  242.     'generic' => $GLOBALS['strGenericOutputAdServer']
  243. ) + $availableOutputAdServerNames;
  244.  
  245. // Prepare an array of HTML elements to display for the form, and
  246. // output using the $oOption object
  247. $aSettings = array(
  248.     array (
  249.         'text'  => $strDeliveryCaching,
  250.         'items' => $aDeliveryCacheSettings
  251.     ),
  252.     array (
  253.         'text'  => $strBannerDelivery,
  254.         'items' => array (
  255.             array (
  256.                 'type'    => 'checkbox',
  257.                 'name'    => 'delivery_acls',
  258.                 'text'    => $strDeliveryAcls
  259.             ),
  260.             array (
  261.                 'type'    => 'checkbox',
  262.                 'name'    => 'delivery_aclsDirectSelection',
  263.                 'text'    => $strDeliveryAclsDirectSelection
  264.             ),
  265.             array (
  266.                 'type'    => 'break'
  267.             ),
  268.             array (
  269.                 'type'    => 'checkbox',
  270.                 'name'    => 'delivery_obfuscate',
  271.                 'text'    => $strDeliveryObfuscate
  272.             ),
  273.             array (
  274.                 'type'    => 'break'
  275.             ),
  276.             array (
  277.                 'type'    => 'checkbox',
  278.                 'name'    => 'delivery_execPhp',
  279.                 'text'    => $strDeliveryExecPhp
  280.             ),
  281.             array (
  282.                 'type'    => 'break'
  283.             ),
  284.             array (
  285.                 'type'    => 'text',
  286.                 'name'    => 'delivery_ctDelimiter',
  287.                 'text'    => $strDeliveryCtDelimiter
  288.             ),
  289.             array (
  290.                 'type'    => 'break'
  291.             ),
  292.             array (
  293.                 'type'    => 'text',
  294.                 'name'    => 'defaultBanner_imageUrl',
  295.                 'text'    => $strGlobalDefaultBannerUrl,
  296.                 'check'   => 'url'
  297.             )
  298.         )
  299.     ),
  300.     array (
  301.         'text'  => $strInvocationDefaults,
  302.         'items' => array (
  303.             array(
  304.                 'type'    => 'select',
  305.                 'name'    => 'delivery_clicktracking',
  306.                 'text'    => $strEnable3rdPartyTrackingByDefault,
  307.                 'items'   => $availableOutputAdServerNames
  308.             )
  309.         )
  310.     ),
  311.     array (
  312.         'text'  => $strP3PSettings,
  313.         'items' => array (
  314.             array (
  315.                 'type'    => 'checkbox',
  316.                 'name'    => 'p3p_policies',
  317.                 'text'   => $strUseP3P
  318.             ),
  319.             array (
  320.                 'type'    => 'break'
  321.             ),
  322.             array (
  323.                 'type'    => 'text',
  324.                 'name'    => 'p3p_compactPolicy',
  325.                 'text'    => $strP3PCompactPolicy,
  326.                 'size'   => 35,
  327.                 'depends' => 'p3p_policies==true'
  328.             ),
  329.             array (
  330.                 'type'    => 'break'
  331.             ),
  332.             array (
  333.                 'type'    => 'text',
  334.                 'name'    => 'p3p_policyLocation',
  335.                 'text'    => $strP3PPolicyLocation,
  336.                 'size'   => 35,
  337.                 'depends' => 'p3p_policies==true',
  338.                 'check'   => 'url'
  339.             )
  340.         )
  341.     ),
  342.     array (
  343.         'text'  => $strWebPath,
  344.         'items' => array (
  345.             array (
  346.                 'type'    => 'url',
  347.                 'name'    => 'webpath_admin',
  348.                 'text'    => $strAdminUrlPrefix,
  349.                 'size'    => 35
  350.             ),
  351.             array (
  352.                 'type'    => 'break'
  353.             ),
  354.             array (
  355.                 'type'    => 'urln',
  356.                 'name'    => 'webpath_delivery',
  357.                 'text'    => $strDeliveryUrlPrefix,
  358.                 'size'    => 35
  359.             ),
  360.             array (
  361.                 'type'    => 'break'
  362.             ),
  363.             array (
  364.                 'type'    => 'urls',
  365.                 'name'    => 'webpath_deliverySSL',
  366.                 'text'    => $strDeliveryUrlPrefixSSL,
  367.                 'size'    => 35
  368.             ),
  369.             array (
  370.                 'type'    => 'break'
  371.             ),
  372.             array (
  373.                 'type'    => 'urln',
  374.                 'name'    => 'webpath_images',
  375.                 'text'    => $strImagesUrlPrefix,
  376.                 'size'    => 35
  377.             ),
  378.             array (
  379.                 'type'    => 'break'
  380.             ),
  381.             array (
  382.                 'type'    => 'urls',
  383.                 'name'    => 'webpath_imagesSSL',
  384.                 'text'    => $strImagesUrlPrefixSSL,
  385.                 'size'    => 35
  386.             )
  387.         )
  388.     ),
  389.     array (
  390.         'text'  => $strDeliveryFilenames,
  391.         'items' => array (
  392.             array (
  393.                 'type'    => 'text',
  394.                 'name'    => 'file_click',
  395.                 'text'    => $strDeliveryFilenamesAdClick,
  396.                 'req'     => true
  397.             ),
  398.             array (
  399.                 'type'    => 'break'
  400.             ),
  401.             array (
  402.                 'type'    => 'text',
  403.                 'name'    => 'file_conversionvars',
  404.                 'text'    => $strDeliveryFilenamesAdConversionVars,
  405.                 'req'     => true
  406.             ),
  407.             array (
  408.                 'type'    => 'break'
  409.             ),
  410.             array (
  411.                 'type'    => 'text',
  412.                 'name'    => 'file_content',
  413.                 'text'    => $strDeliveryFilenamesAdContent,
  414.                 'req'     => true
  415.             ),
  416.             array (
  417.                 'type'    => 'break'
  418.             ),
  419.             array (
  420.                 'type'    => 'text',
  421.                 'name'    => 'file_conversion',
  422.                 'text'    => $strDeliveryFilenamesAdConversion,
  423.                 'req'     => true
  424.             ),
  425.             array (
  426.                 'type'    => 'break'
  427.             ),
  428.             array (
  429.                 'type'    => 'text',
  430.                 'name'    => 'file_conversionjs',
  431.                 'text'    => $strDeliveryFilenamesAdConversionJS,
  432.                 'req'     => true
  433.             ),
  434.             array (
  435.                 'type'    => 'break'
  436.             ),
  437.             array (
  438.                 'type'    => 'text',
  439.                 'name'    => 'file_frame',
  440.                 'text'    => $strDeliveryFilenamesAdFrame,
  441.                 'req'     => true
  442.             ),
  443.             array (
  444.                 'type'    => 'break'
  445.             ),
  446.             array (
  447.                 'type'    => 'text',
  448.                 'name'    => 'file_image',
  449.                 'text'    => $strDeliveryFilenamesAdImage,
  450.                 'req'     => true
  451.             ),
  452.             array (
  453.                 'type'    => 'break'
  454.             ),
  455.             array (
  456.                 'type'    => 'text',
  457.                 'name'    => 'file_js',
  458.                 'text'    => $strDeliveryFilenamesAdJS,
  459.                 'req'     => true
  460.             ),
  461.             array (
  462.                 'type'    => 'break'
  463.             ),
  464.             array (
  465.                 'type'    => 'text',
  466.                 'name'    => 'file_layer',
  467.                 'text'    => $strDeliveryFilenamesAdLayer,
  468.                 'req'     => true
  469.             ),
  470.             array (
  471.                 'type'    => 'break'
  472.             ),
  473.             array (
  474.                 'type'    => 'text',
  475.                 'name'    => 'file_log',
  476.                 'text'    => $strDeliveryFilenamesAdLog,
  477.                 'req'     => true
  478.             ),
  479.             array (
  480.                 'type'    => 'break'
  481.             ),
  482.             array (
  483.                 'type'    => 'text',
  484.                 'name'    => 'file_popup',
  485.                 'text'    => $strDeliveryFilenamesAdPopup,
  486.                 'req'     => true
  487.             ),
  488.             array (
  489.                 'type'    => 'break'
  490.             ),
  491.             array (
  492.                 'type'    => 'text',
  493.                 'name'    => 'file_view',
  494.                 'text'    => $strDeliveryFilenamesAdView,
  495.                 'req'     => true
  496.             ),
  497.             array (
  498.                 'type'    => 'break'
  499.             ),
  500.             array (
  501.                 'type'    => 'text',
  502.                 'name'    => 'file_xmlrpc',
  503.                 'text'    => $strDeliveryFilenamesXMLRPC,
  504.                 'req'     => true
  505.             ),
  506.             array (
  507.                 'type'    => 'break'
  508.             ),
  509.             array (
  510.                 'type'    => 'text',
  511.                 'name'    => 'file_local',
  512.                 'text'    => $strDeliveryFilenamesLocal,
  513.                 'req'     => true
  514.             ),
  515.             array (
  516.                 'type'    => 'break'
  517.             ),
  518.             array (
  519.                 'type'    => 'text',
  520.                 'name'    => 'file_frontcontroller',
  521.                 'text'    => $strDeliveryFilenamesFrontController,
  522.                 'req'     => true
  523.             ),
  524.             array (
  525.                 'type'    => 'break'
  526.             ),
  527.             array (
  528.                 'type'    => 'text',
  529.                 'name'    => 'file_flash',
  530.                 'text'    => $strDeliveryFilenamesFlash,
  531.                 'req'     => true
  532.             )
  533.         )
  534.     )
  535. );
  536. $oOptions->show($aSettings, $aErrormessage);
  537.  
  538. // Display the page footer
  539. phpAds_PageFooter();
  540.  
  541. ?>

And go to OpenX/www/admin/lib-maintenance.inc.php and update the file code with below

  1. < ?php
  2.  
  3. /*
  4. +—————————————————————————+
  5. | OpenX v2.8                                                                |
  6. | ==========                                                                |
  7. |                                                                           |
  8. | Copyright (c) 2003-2009 OpenX Limited                                     |
  9. | For contact details, see: http://www.openx.org/                           |
  10. |                                                                           |
  11. | This program is free software; you can redistribute it and/or modify      |
  12. | it under the terms of the GNU General Public License as published by      |
  13. | the Free Software Foundation; either version 2 of the License, or         |
  14. | (at your option) any later version.                                       |
  15. |                                                                           |
  16. | This program is distributed in the hope that it will be useful,           |
  17. | but WITHOUT ANY WARRANTY; without even the implied warranty of            |
  18. | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             |
  19. | GNU General Public License for more details.                              |
  20. |                                                                           |
  21. | You should have received a copy of the GNU General Public License         |
  22. | along with this program; if not, write to the Free Software               |
  23. | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA |
  24. +—————————————————————————+
  25. $Id: lib-maintenance.inc.php 62345 2010-09-14 21:16:38Z chris.nutting $
  26. */
  27.  
  28. // Required files
  29. require_once MAX_PATH . '/lib/max/language/Loader.php';
  30.  
  31. // Load the required language files
  32. Language_Loader::load('maintenance');
  33.  
  34. function phpAds_MaintenanceSelection($subSection, $mainSection='maintenance')
  35. {
  36.     global
  37.          $phpAds_TextDirection
  38.         ,$strBanners
  39.         ,$strCache
  40.         ,$strChooseSection
  41.         ,$strPriority
  42.         ,$strSourceEdit
  43.         ,$strStats
  44.         ,$strStorage
  45.         ,$strMaintenance
  46.         ,$strCheckForUpdates
  47.         ,$strViewPastUpdates
  48.         ,$strEncoding
  49.         ,$strDeliveryLimitations
  50.         ,$strAppendCodes
  51.         ,$strMenus
  52.         ,$strPlugins
  53.     ;
  54.  
  55. ?>
  56. <script language="JavaScript">
  57. <!–
  58. function maintenance_goto_section()
  59. {
  60.     s = document.maintenance_selection.section.selectedIndex;
  61.  
  62.     s = document.maintenance_selection.section.options[s].value;
  63.     document.location = '<?php echo $mainSection; ?>-' + s + '.php';
  64. }
  65. // –>
  66. </script>
  67. < ?php
  68.     $conf =& $GLOBALS['_MAX']['CONF'];
  69.     $pref =& $GLOBALS['_MAX']['PREF'];
  70.  
  71.     echo "<table border='0' width='100%' cellpadding='0' cellspacing='0'>";
  72.     echo "<tr><form name='maintenance_selection'><td height='35'>";
  73.     echo "<b>".$strChooseSection.":&nbsp;</b>";
  74.     echo "<select name='section' onChange='maintenance_goto_section();'>";
  75.  
  76.     if (OA_Permission::isAccount(OA_ACCOUNT_ADMIN)) {
  77.         if ($mainSection == 'updates') {
  78.             echo "<option value='product'".($subSection == 'product' ? ' selected' : '').">".$strCheckForUpdates."</option>";
  79.             echo "<option value='history'".($subSection == 'history' ? ' selected' : '').">".$strViewPastUpdates."</option>";
  80.         } else {
  81.             echo "<option value='maintenance'".($subSection == 'maintenance' ? ' selected' : '').">".$strMaintenance."</option>";
  82.             echo "<option value='banners'".($subSection == 'banners' ? ' selected' : '').">".$strBanners."</option>";
  83.             echo "<option value='priority'".($subSection == 'priority' ? ' selected' : '').">".$strPriority."</option>";
  84.  
  85.             $login = 'ftp://' . $conf['store']['ftpUsername'] . ':' . $conf['store']['ftpPassword'] . '@' .
  86.                      $conf['store']['ftpHost'] . '/' . $conf['store']['ftpPath'];
  87.             if ($conf['allowedBanners']['web'] == true && (($conf['store']['mode'] == 0 &&
  88.                 $conf['store']['webDir'] != '') || ($conf['store']['mode'] == 1 &&
  89.                 $login != '')) && $conf['webpath']['images'] != '')
  90.                 echo "<option value='storage'".($subSection == 'storage' ? ' selected' : '').">".$strStorage."</option>";
  91.  
  92. //            if (!isset($conf['delivery']['cache']) || $conf['delivery']['cache'] != 'none')
  93. //                echo "<option value='cache'".($subSection == 'zones' ? ' selected' : '').">".$strCache."</option>";
  94.  
  95.             if ($conf['delivery']['acls']) {
  96.                 echo "<option value='acls'".($subSection == 'acls' ? ' selected' : '').">".$strDeliveryLimitations."</option>";
  97.             }
  98.  
  99.             echo "<option value='appendcodes'".($subSection == 'appendcodes' ? ' selected' : '').">".$strAppendCodes."</option>";
  100.             echo "<option value='encoding'".($subSection == 'encoding' ? ' selected' : '').">$strEncoding</option>";
  101.             echo "<option value='menus'".($subSection == 'menus' ? ' selected' : '').">".$strMenus."</option>";
  102.             echo "<option value='plugins'".($subSection == 'plugins' ? ' selected' : '').">".$strPlugins."</option>";
  103.         }
  104.     }
  105.  
  106.     // Switched off
  107.     // echo "<option value='finance'".($subSection == 'finance' ? ' selected' : '').">Finance</option>";
  108.  
  109.     echo "</select>&nbsp;<a href='javascript:void(0)' onClick='maintenance_goto_section();'>";
  110.     echo "<img src='" . OX::assetPath() . "/images/".$phpAds_TextDirection."/go_blue.gif' border='0'/></a>";
  111.     echo "</td></form></tr>";
  112.       echo "";
  113.  
  114.     phpAds_ShowBreak();
  115. }
  116.  
  117. ?>

Congratulations you’re done and you can now run your site، please let me know if you need any hep.

Media -> Anything that can appear beautiful and true (even a car bomb explosion)

Damascus

Arab region bubble … My view

What you will read here is just an idea and personal analysis, if you do not like it stop reading at this point.

 

What is occurring in the region now is that there are a large number of projects  with high costs, zero profitability and non-existent returns.

No names here, but if you want a list, email me :D

The main objective of most “start-ups” in the region is to get funding to pay salaries, not to finance expansion or move to the next phase.

We now have projects in the region pumping millions of dollars per month for high salaries, huge marketing budgets, crazy advertising, premium office costs …. etc.  Few people in the region have the goal to build a profitable, sustainable business. Everyone is spend like crazy to build THE platform that will attract a buyer/investor from the West who will rescue their finances and somehow magically start turning their business into a profitable one.

This way of thinking and action can succeed by luck several times, but it is impossible for some of these “cool” or flashy projects to continue to exist. Looking at some of these marketing budgets I think the Middle East is ready for our own Pets.com. And it will not be just one!!

And this will happen soon and will be disastrous for many people. But it would be useful to correct the industry and get all the crazy dreamers out. Keep entrepreneurs who aim to build successful, REAL projects in.

Silaal is a free open source e-commerce system coming soon

I have worked on many of the e-commerce systems like Magneto and Prestashop, and I built big e-commerce systems using a framework like Zend and Kohana but every time I rebuild many  same parts again and solve same problems related to shipping integration and Arabic language support and local payment Gateways integrations.

So a few days I ago I came up with the idea of ​​building an arabic e-commerce system using the fastest PHP framework, Yii.
I met with some friends (Moayed – Nawras – Issam) who loved the idea. We have started working on it, and we hope to launch a first version after a short period. Of course, the project is open to all developers.

 

Project site: http://code.google.com/p/silaal/

 

Why ArabNet disgusting!

This post is not about the positive features of ArabNet (yes, there are some). I will speak only about the bad points I see at the conference:

  1. Pricing is irresponsible and shows ArabNet is a business only. The best price, for students, is $350!!  
  2. Program does not contain any panels on open source initiatives; there are no special activities for youth or university students.
  3. Everyone who goes there goes for tourism (like me) or because their companies forced them to it.
  4. Beautiful thing is that the conference organizers do not have any idea about the Internet or technology (you can see this by the way they have arranged the program of the Developer Day).
  5. Money first, not experience for who gets to speak on the panels. Actually the whole program is built around the sponsors who pay $$!!
  6. ArabNet, but one does not speak with you in Arabic and all the posts will be in English (or French in some cases).
  7. There are no important programmers and developers. None of the Arabs working on the open-source project of “Oajuobh” and Arabeyes will be there. You will only meet people who want to pass the time pretending to debate universally accepted theories.
And through these points you can conclude the following:
1 – ArabNet is a 100% commercial activity
2 – Large companies here are will to pay for the stupid things, but they will not support any useful projects.
Arab region will continue to be late for the tech world as long as we have a silly companies like the Google team who is willing to pay tens of thousands to be a “sponsor partner” for the event but they do not bother to provide technical support for Arabs developers of Android.

OnTimeUpdates: schedule updates to Twitter and Facebook


Site works OnTimeUpdates to deploy Comments directly to Facebook and Twitter once without having to navigate between them to spread this one, can be at the site also schedule updates autonomic both the Facebook and Twitter to publish at a certain time and will be published automatically, the site also you can upload images to your Facebook Facebook and the lifting of such scheduling.

To visit the website: http://ontimeupdates.com

New project Play Wii online “using WebBrowsers”

The idea of the project is to create a website on the Internet for the Games of collective and individual, using Wii .
And the construction of two sections:
1 – server system linked Wii processors.
2 – Client (Flash) to activate the browser Highlighted Camera

We still plan the project will be an open-source can be for all involved to work or ideas
Wait for your comments.

 

 

Elephant operating system.

I’m began to work on this distribution for several weeks intermittently and now I can get a stable system, the elephant is an operating system based on Linux addressed only to programmers and developers is derived from the Debian distribution and use Boot Susie and Gnome desktop,
This distribution contains the basic tools and software for web developers and had been introduced by some of the tools of artificial intelligence.
The list of programs in  Elephant OS:
  1. lamp server
  2. apache2
  3. chkrootkit
  4. clisp
  5. compiz
  6. dvd+rw-tools
  7. eclipse
  8. filezilla
  9. finger
  10. ftp
  11. gcc-c++
  12. gedit
  13. gimp
  14. git-svn
  15. jedit
  16. mono-tools
  17. MozillaFirefox
  18. mtools
  19. mysql-administrator
  20. mysql-community-server
  21. mysql-gui-tools
  22. netcat
  23. NetworkManager
  24. nmap
  25. ntp
  26. Lisp
  27. php5
  28. pidgin
  29. planner
  30. samba
  31. samba-client
  32. subversion
  33. tcpdump
  34. telnet
  35. Terminal
  36. tomboy
  37. vim
  38. wget
  39. whois
  40. wine
  41. wireless-tools
  42. zenmap
  43. zip
  44. zypper

 

Screenshots:


Loomnit share anything, anywhere “Chrome extension ” 1.0 :)

Loomn.it is an easy to use, online sharing service that provides users with a simple way to share with anyone, links, emails, images, video, documents and other digital content.
With a cup of morning coffee, decided to build Chrome extension to the service had worked on it before (Loomn.it) and the end of the coffee the extension was ready Added For use :)
I hope everyone’s tested and if there is any comments or suggestions you can write me here
A beautiful day for all

The first Neuron Transistor

After working more than 4 years this is the first image

The project will change the world

This is what Thottagh only to run

This is what Thottagh only to run

Plug legs were made of gold

Plug legs were made of gold

Like a normal transistor, but he has more legs

Like a normal transistor, but he has more legs

Yes, this is the size you believe

Yes, this is the size you believe