Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts

Tuesday, May 2, 2017

Vagrantfile for latest magento 2 (version 2.16) and ubuntu (Ubuntu 14.04.5 LTS)

I have just upload Vagrantfile for latest magento (2.16) and latest Ubuntu (bento/ubuntu-14.04) to github so that interested readers can install the latest magento for development via Vagrant on their computer:

Magento & Vagrant
The github repo contains the Vagrantfile and Vagrantfile.config.yml adopted from the "Magento Developer Guide" book but updated based on the trial-and-errors with the latest magento, ubuntu and PHP
The objective is to address several issues with the original Vagrantfile provided by "Magento Developer Guide" so that it is compatible with the latest magento (current version 2.16) and Ubuntu (current version: Ubuntu 14.04.5 LTS)
Some known issues with the original Vagrantfile provided by "Magento Developer Guide" are:
  • The vm.box "ubuntu/vivid64" for vagrant is not longer provided
  • The default PHP version (7.1) provided by latest ubuntu (after running apt-get update on bento/ubuntu-14.04) is not compatible with magento 2.16 due to the issues with mcrypt no longer supported in PHP 7.1
  • php5.6-mbstring and php5.6-zip are needed for the magento 2.16 to work correctly

Version

The following list the version of the various softwares installed by the Vagrantfile on the ubuntu VM:
  • vm.box: bento/ubuntu-14.04
  • magento: magento 2 (version: 2.16)
  • PHP: 5.6
  • MySQL: 5.6
Currently the Vagrantfile is tested to be working on host computer which is Windows 10

Usage

  • Install VirtualBox
  • Install Vagrant
  • Obtain the magento public and private secret keys (Follow this link) and replace the "[magent_public_key]" and "[magento_private_key]" in Vagrantfile.config.yml with the obtained keys
  • Obtain a github oauth access key (Follow this link and replace the "[github_oauth]" in Vagrantfile.config.yml with the obtained github oauth token
  • Change the "email@change.me" in Vagrantfile.config.yml to your email of choice
  • Change the "[magento_host_path]" in Vagrantfile.config.yml to your local path on your host computer on which you want the magento files to be installed
  • Run the following command on your host computer:
git clone https://github.com/chen0040/vagrant-magento-2.16.git
cd vagrant-magento-2.16
vagrant up
  • Add the line "192.168.10.10 magento.box" to /etc/hosts on your host computer (If you host computer is Windows, then the hosts file is located at C:\Windows\System32\drivers\etc\hosts)
  • Open your browser and enter "http://magento.box" (To change this to your url of choice, replace it in the Vagrantfile.config.yml)
  • To login to the vagrant vm box, run the command "vagrant ssh". If you are using putty, ssh to 192.168.10.10 (username: vagrant, password: vagrant)

Issues and Solutions

If you encounter some of the issues when running Vagrantfile, you can refer to the following:
  • Issue: Vagrant was unable to mount VirtualBox shared folders. This is usually because the filesystem "vboxsf" is not available. This filesystem is made available via the VirtualBox Guest Additions and kernel module.
Solution: Run the following command:
vagrant plugin install vagrant-vbguest

Saturday, December 27, 2014

Simple page to download file in PHP

Below is the code snippet in PHP which download a file from the server.

<php?
// http headers for zip downloads
$localfilename='myfileOnServer.zip';
$filename='myfilenameClient.zip';
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($localfilename));
ob_end_flush();
@readfile($localfilename);
?>

The above codes download the file named "myFileOnServer.zip" to the client with default save file "myfilenameClient.zip".

The above download may not work if the file "myFileOnServer.zip" is larger than the default settings in php.ini (PHP 4) or php5.ini (PHP 5). To solve this download the php.ini and php5.ini from your server and add the following lines:

Upload_max_filesize  = 1500M
Max_input_time  = 1000
Memory_limit = 640M
Max_execution_time = 1800
Post_max_size = 2000M


Wednesday, January 15, 2014

CTabcontrol with each tab containing a widget (Yii)

Suppose in Yii, we want to pass the content of a widget to a tab in the tab control

<?php
ob_start();
$this->widget('zii.widgets.CListView', array(
    'dataProvider'=>$vulnerdataProvider,
    'itemView'=>'_latest_vulner'
));
$tab1Content=ob_get_contents();
ob_end_clean();

$this->widget('zii.widgets.jui.CJuiTabs',array(
    'tabs'=>array(
        'Tab1'=> array('content' => $tab1Content,'id' => 'tab1'),
        'tab2'=>array('content'=>'Content for tab 2', 'id'=>'tab2'),
    ),
    // additional javascript options for the tabs plugin
    'options'=>array(
        'collapsible'=>true,
    ),
));
?>

CTabView with partial view in each tab (Yii)

Suppose using Yii framework and we want to add a tab control in which each tab shows a partial view, the following codes shows how this can be done:

<?php
$nc_view=$this->renderPartial('_viewNodeConfig', array('project'=>$model), $return=true);
$user_view=$this->renderPartial('_viewUser', array('project'=>$model), $return=true);
$sim_view=$this->renderPartial('_viewSimulation', array('project'=>$model), $return=true);

$this->widget('CTabView',array(
    'activeTab'=>'tab2',
    'tabs'=>array(
        'tab1'=>array(
            'title'=>'Users',
            'content'=>$user_view,
        ),
        'tab2'=>array(
            'title'=>'Node Types',
            'content'=>$nc_view,
        ),
        'tab3'=>array(
            'title'=>'Simulations',
            'content'=>$sim_view,
        )
    ),
    'htmlOptions'=>array(
        //'style'=>'width:500px;'
    )
));
?>
In the above codes, the _viewNodeConfig.php is a partial view which looks like the following:
<?php 
$node_configs=new CActiveDataProvider('NodeConfig', 
    array(
     'criteria'=>array( 
      'condition'=>'audit_project_id=:projectId', 
      'params'=>array(':projectId'=>$project->id),
     ),
     'pagination'=>array( 
      'pageSize'=>4,
     ), 
    )
   );
   
$this->widget('zii.widgets.CListView', array(
 'dataProvider'=>$node_configs,
 'viewData'=>array('project'=>$project),
 'itemView'=>'/nodeConfig/_view',
)); 
?>

Sunday, January 12, 2014

Cascade delete in Yii model by overriding beforeDelete() and afterDelete() method

Yii provides Cascade using relations with the cascade constraint defined in database, which allows the user to delete cascade data when a model is deleted. However, in some cases, the user may want to perform this on his own (e.g. there may be some sophisticated conditioning involved during the cascade delete, or other resources such as images to be deleted associated with the model). In such a case, the user can override the beforeDelete() and afterDelete() method to perform the clean up (e.g. delete images and cascaded objects associated with the deleted model). Suppose we have a model class Project, and we want to delete a set of users as well as an image associated with the deleted Project model:

Step 1: Override beforeDelete()

Add a variable idCache to the User model class in protected/models/User.php:
private $idCache;
Next override the beforeDelete() method to assign User->id to idCache:
public function beforeDelete()
{
 $this->idCache = $this->id;

 return parent::beforeDelete();
}
The purpose of having idCache is to cache the User->id attribute in the beforeDelete() method and use it in the afterDelete() method (since the $User->id will no longer be available in the afterDelete() method

Step 2: Override afterDelete()

Next we will delete the associated users and image to the deleted Project model by overriding the afterDelete() method:
public function afterDelete()
{
 $criteria = new CDbCriteria(array(
   'condition' => 'project_id=:projectId',
   'params' => array(
    ':projectId' => $this->idCache),
  ));

 $users_associated_with_project = User::model()->findAll($criteria);

 foreach ($users_associated_with_project as $user)
 {
  $user->delete();
 }
 
 $filename=$this->getImagePath($this->idCache);
 if(file_exists($filename))
 {
  unlink($filename);
 }

 parent::afterDelete();
}

Create CListView of a model class in another model's view (Yii)

Suppose we have two models: Project and User, in which each Project owns a number of Users. We wish to display a list of associated users in the project instance's view

Modify the protected/views/project/view.php by adding the following line in the script file:

<?php $this->renderPartial('_viewUser', array('project'=>$model)); ?>

Next create a partial view protected/views/project/_viewUser.php with the following codes for its implementation:

<?php 
$users=new CActiveDataProvider('User', 
    array(
     'criteria'=>array( 
      'condition'=>'audit_project_id=:projectId', 
      'params'=>array(':projectId'=>$project->id),
     ),
    ),
    array( 
     'pagination'=>array( 
      'pageSize'=>20,
     ), 
    )
   );
   
$this->widget('zii.widgets.CListView', array(
 'dataProvider'=>$users,
 'viewData'=>array('project'=>$project),
 'itemView'=>'/user/_view',
)); 
?>

Cascade create a model and attach it to another model in Controller in a One-to-Many relationship (Yii)

Suppose we have a situation where we a set of users, each of which belong to a particular project. In Yii, we already create two models, namely Project and User. The User model class contains an attribute project_id, which is the id attribute value of the associated Project model. Now a user cannot be created without knowing the project_id it is associated with

Step 1:

In the protected/views/project/view.php, add a link to create user associated with the project:

<?php echo CHtml::link(CHtml::encode('Create user under the project'), array('user/create', 'project_id'=>$model->id)); ?>
The project_id allows the UserController (i.e. the controller associated with the User model) to identify the project_id to which the created user should be associated with.

Step 2:

In the protected/controllers/UserController.php, add a private member variable _project:

private $_project = null;

Next in the UserController.php, find the method filters(), and add one line for projectContext filter:

/**
 * @return array action filters
 */
public function filters()
{
 return array(
  'accessControl', // perform access control for CRUD operations
  'projectContext + create index admin', //check to ensure valid event context
 );
}

Next in the UserController.php, defines the following methods:

public function filterProjectContext($filterChain) 
{
 //set the project identifier based on either the GET or POST input
 //request variables, since we allow both types for our actions 
 $project_id = null;
 if(isset($_GET['project_id'])) 
  $project_id = $_GET['project_id'];
 else
  if(isset($_POST['project_id'])) 
   $project_id = $_POST['project_id'];
 $this->loadProject($project_id);
 //complete the running of other filters and execute the requested action
 $filterChain->run();
}

protected function loadProject($project_id) 
{ 
 //if the project property is null, create it based on input id 
 if($this->_project===null) 
 {
  $this->_project=Project::model()->findbyPk($project_id); 
  if($this->_project===null)
  { 
   throw new CHttpException(404,'The requested project does not exist.'); 
  }
 }
 return $this->_project;
}
The above method allows Yii code to create and assign the _project with the content from database using the project_id passed in from Step 1. As a result, before the actionCreate() method is invoked, the _project is already properly initialized based project_id attribute passed in. The final step is to assign $user->project_id in the actionCreate() method of the UserController class, as shown below:
public function actionCreate()
{
 $model=new User;
 $model->project_id=$this->_project->id;

 // Uncomment the following line if AJAX validation is needed
 // $this->performAjaxValidation($model);

 if(isset($_POST['User']))
 {
  $model->attributes=$_POST['User'];
  if($model->save())
   $this->redirect(array('view','id'=>$model->id));
 }

 $this->render('create',array(
  'model'=>$model,
 ));
}

Use of beforeSave() and beforeValidate() for Yii models when writing to database

beforeValidate() is very handy for performing validation of the model before it is save to the database in Yii, below shows an example of how it is used in a Yii model class Project

protected function beforeValidate() 
{
 if($this->isNewRecord)
 {
  // set the create date, last updated date and the user doing the creating
  $this->audit_create_time=$this->audit_update_time=new CDbExpression('NOW()');
  $this->audit_update_time=new CDbExpression('NOW()'); 
  
  $existing_proj=Project::model()->find('projname=?', array($this->projname));
  if(isset($existing_proj))
  {
   return false;
  }
 }
 else
 {
  //not a new record, so just set the last updated time and last updated user id
  $this->audit_update_time=new CDbExpression('NOW()'); 
 }
 
 return parent::beforeValidate();
}
The above code checks whether a project with the same projname already exist in the database, if yes, then the validation return false, it also updates the create time and update time depending on whether the action is to create or update a project.

beforeSave() is useful to perform additional data processing before a model is saved to the database, below shows an example of how it is used in a Yii model class User

public function beforeSave()
{  
 if($this->isNewRecord)
 {
  $this->audit_db_create_time=$this->audit_db_update_time=new CDbExpression('NOW()');
 }
 else
 {
  $this->audit_db_update_time=new CDbExpression('NOW()'); 
 }
 
 $this->password=$this->encrypt($this->password);
 
 return TRUE;
}
The above code encrypt the password before it is saved to the database, it also updates the create time and update time for writing the model to the database depending on whether the action is to create or update a user

Some useful HTML elements in Yii

Create Html Link in Yii

  1. The code below creates a html link to user view which has id = 23
    <?php echo CHtml::link(CHtml::encode('View User with ID = 23'), array('user/view', 'id'=>23)); ?>
    
  2. The code below creates a html link to the html form for creating a user
  3. <?php echo CHtml::link(CHtml::encode('Create User'), array('user/create')); ?>
    

Create Html Label in Yii

The code below creates a html label

<?php echo CHtml::label(CHtml::encode('Some Text'), 'Some Text'); ?>

Create Html ComboBox in Yii

The code below creates a html combobox

<?php echo $form->dropDownList($model, 'field_name', array(1=>'test1', 2=>'test2'));?>
The code belows creates a html combobox with list data populating dropdown from database values
<?php echo $form->dropDownList($model,'node_types_id', CHtml::listData(NodeTypes::model()->findAll(array('order' => 'name')),'id','name'));?>

Sunday, August 11, 2013

Javascript Video Player to play AVI, WMV, and other formats such as MP4

There are quite a number of javascript-based video player which leverage either HTML5 or flash player to player video files from the server. However, majority of them does not support playback of file format such as AVI and WMV. This post shows how one can create a simple page in javascript and PHP that support playback of most video formats including AVI and WMV.

Step 1: Download Flowplayer
Download the flow player from the following link:

http://flowplayer.org/download/

unzip the flowplayer to the folder "flowplayer" below your application root directory.

Step 2: Implement PHP video player page

Implement a video player page in PHP that playback the video, the source code of the PHP is shown below:

<?php

$folder_name=$_GET['dirno'];
$video_name=$_GET['vid'];

$path_parts = pathinfo($video_name);
$video_format= $path_parts['extension']; 
?>

<!DOCTYPE html>
<html>
<head>
  <title>Meme Analytics Video Demos</title>

  <?php if($video_format=='avi' || $video_format=='wmv'):?>
  <?php else: ?>
   <!-- player skin -->
   <link rel="stylesheet" type="text/css" href="flowplayer/skin/minimalist.css">

   <!-- site specific styling -->
   <style type="text/css">
   body { font: 12px "Myriad Pro", "Lucida Grande", sans-serif; text-align: center; padding-top: 5%; }
   .flowplayer { width: 80%; }
   </style>

   <!-- flowplayer depends on jQuery 1.7.1+ (for now) -->
   <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

   <!-- include flowplayer -->
   <script type="text/javascript" src="flowplayer/flowplayer.min.js"></script>
  <?php endif; ?>

</head>
<body>
  <?php if($video_format=='avi' || $video_format=='wmv'):?>
  <object classid="clsid:67DABFBF-D0AB-41fa-9C46-CC0F21721616" width="320" height="260" codebase="http://go.divx.com/plugin/DivXBrowserPlugin.cab">

  <param name="custommode" value="none" />

   <param name="previewImage" value="image.png" />
   <param name="autoPlay" value="false" />
   <param name="src" value="<?php echo $folder_name.'/'.$video_name; ?>" />

 <embed type="video/divx" src="<?php echo $folder_name.'/'.$video_name; ?>" custommode="none" width="320" height="260" autoPlay="false"  previewImage="image.png"  pluginspage="http://go.divx.com/plugin/download/">
 </embed>
 </object>
 <br />No video? <a href="http://www.divx.com/software/divx-plus/web-player" target="_blank">Download</a> the DivX Plus Web Player.
  <?php else: ?>
  <!-- the player -->
   <div class="flowplayer" data-swf="flowplayer/flowplayer.swf" data-ratio="0.4167">
      <video>
          <source src="http://xxx-xxx.com/demo/videos/<?php echo $folder_name.'/'.$video_name; ?>" type='video/<?php echo $video_format; ?>' />
         
      </video>
   </div>
  <?php endif; ?>
</body>
<html>

The PHP player page accept to parameters from the URL: dirno and vid, which are the directory name and the video filename, it then checks the extension of the video file, if the file is a AVI or WMV file, it invokes the DIVX web player, otherwise, the flowplayer is used to play the video.

Step 3: Use VLC instead of DIVX to player AVI online

In case the DIVX web player does not work with your AVI files, you can also try other options, below is the same PHP script rewritten to use VLC player for AVI.

<?php

$folder_name=$_GET['dirno'];
$video_name=$_GET['vid'];

$path_parts = pathinfo($video_name);
$video_format= $path_parts['extension']; 
?>

<!DOCTYPE html>
<html>
<head>
  <title>Video Demos</title>

  <?php if($video_format=='avi' || $video_format=='wmv'):?>
  <?php else: ?>
   <!-- player skin -->
   <link rel="stylesheet" type="text/css" href="flowplayer/skin/minimalist.css">

   <!-- site specific styling -->
   <style type="text/css">
   body { font: 12px "Myriad Pro", "Lucida Grande", sans-serif; text-align: center; padding-top: 5%; }
   .flowplayer { width: 80%; }
   </style>

   <!-- flowplayer depends on jQuery 1.7.1+ (for now) -->
   <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

   <!-- include flowplayer -->
   <script type="text/javascript" src="flowplayer/flowplayer.min.js"></script>
  <?php endif; ?>

</head>
<body>
  <?php if($video_format=='avi' || $video_format=='wmv'):?>
  
  <object type="application/x-vlc-plugin" pluginspage="http://www.videolan.org" data="http://xxx-xxx.com/demo/videos/<?php echo $folder_name.'/'.$video_name; ?>" width="400" height="300" id="video1">
     <param name="movie" value="http://xxx-xxx.com/demo/videos/<?php echo $folder_name.'/'.$video_name; ?>"/>
     <embed type="application/x-vlc-plugin" name="video1"
     autoplay="no" loop="no" width="400" height="300"
     target="http://xxx-xxx.com/demo/videos/<?php echo $folder_name.'/'.$video_name; ?>" />
  <br />
     <a href="http://xxx-xxx.com/demo/videos/<?php echo $folder_name.'/'.$video_name; ?>">Download Video</a>
  <br />
   Video Not Played? download <a href="http://www.videolan.org" target="_blank">VLC Player</a> 
</object>

  
  <?php else: ?>
  <!-- the player -->
   <div class="flowplayer" data-swf="flowplayer/flowplayer.swf" data-ratio="0.4167">
      <video>
          <source src="http://xxx-xxx.com/demo/videos/<?php echo $folder_name.'/'.$video_name; ?>" type='video/<?php echo $video_format; ?>' />
      </video>
   </div>
  <?php endif; ?>
</body>
</html>


Monday, August 5, 2013

Enumerate files in a directory using PHP

<?php

if ($handle = opendir('./files')) 
{
    while (false !== ($entry = readdir($handle))) 
 {
  echo $entry;
    }

    closedir($handle);
}
?>

Data Encryption in PHP

The encryption.inc includes the encryption utility which prevents the user from deciphering the token. The source codes of the encryption.inc is shown below:

<?php

class Encryption {
    var $skey = '[YOUR-SECRET-KEY]';

    public  function safe_b64encode($string) {
        $data = base64_encode($string);
        $data = str_replace(array('+','/','='),array('-','_',''),$data);
        return $data;
    }

    public function safe_b64decode($string) {
        $data = str_replace(array('-','_'),array('+','/'),$string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    public  function encode($value){ 
        if(!$value){return false;}
        $text = $value;
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, $text, MCRYPT_MODE_ECB, $iv);
        return trim($this->safe_b64encode($crypttext)); 
    }

    public function decode($value){
        if(!$value){return false;}
        $crypttext = $this->safe_b64decode($value); 
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
        return trim($decrypttext);
    }
}

?>
To use the above facility, the following is the demo
$converter = new Encryption;
$raw='Hello World';
$encoded = $converter->encode($raw);
$decoded = $converter->decode($encoded);  

Send HTML Email in PHP

ini_set("SMTP","[YOUR-EMAIL-SERVER-ADDRESS]");  // this line 184 for me  

$to      = '[YOUR-TO-EMAIL-ACCOUNT]';
$subject = 'This is the subject line';
$message = '

Hello World!


'; $message .=''; $headers = "MIME-Version: 1.0" . "\r\n"; $headers .= "Content-type:text/html;charset=iso-8859-1" . "\r\n"; $headers .= 'From: <from@example.com>' . "\r\n"; $headers .= 'Cc: cc@example.com' . "\r\n"; mail($to, $subject, $message, $headers);

A simple tutorial on creating software registration and download page with encrypted one day valid token using PHP

This tutorial shows how to create a registration page that will automatically send user an automatically generated software download link using encrypted one day valid token after user register. For simplicity, the database logging is omitted.

Step 1: Create a registration form page
Create a simple registration form page registration.htm as in the follows:

<html>
<body>
Software Application Download Registration <br>

<form id="regForm" action="submit.php" method="post">

<table>
  <tbody>
  <tr>
    <td><label for="fname">First Name:</label></td>
    <td><div class="input-container"><input name="fname" id="fname" type="text" /></div></td>
  </tr>
  <tr>
    <td><label for="lname">Last Name:</label></td>
    <td><div class="input-container"><input name="lname" id="lname" type="text" /></div></td>
  </tr>
  <tr>
    <td><label for="email">Your Email:</label></td>
    <td><div class="input-container"><input name="email" id="email" type="text" /></div></td>
  </tr>
  <tr>
    <td><label for="company">Company:</label></td>
    <td><div class="input-container"><input name="company" id="company" type="text" /></div></td>
  </tr>
  <tr>
  <td> </td>
  <td><input type="submit" class="greenButton" value="Register and Download" /><img id="loading" src="img/ajax-loader.gif" alt="working.." />
</td>
  </tr>
  
  
  </tbody>
</table>

</form>
</body>
</html>

Step 2: Create registration submission processing server script in PHP
Create the submit.php page which processes the registration information from the  registration.htm page. the submit.php page sends the registered user an email with a link to download the software, the link is valid for the current date (using the concept of token), the submit.php also cc the email to [YOUR-EMAIL-CC-ACCOUNT] (As this is a simple demo, the validation of registration information is not included here)

<?php

require_once('encryption.inc');

$token="dfjsl@ew".date('Ymd')."oqiej".date('Y')."!#@#@1".date('m')."2331";

$converter = new Encryption;
$encoded = $converter->encode($token);

$mail_server="[YOUR-MAIL-SERVER-IP-ADDRESS]";

ini_set("SMTP",$mail_server);  

$to      = $_POST['email'];
$cc     = '[YOUR-EMAIL-CC-ACCOUNT]';

$subject = 'XXX Application Download';
$message = '<html><body><h2>User registration information: </h2><br />';
$message .= '<table>';
$message .='<tr><td><b>First Name:</b></td><td>'.$_POST['fname'].'</td></tr>';
$message .='<tr><td><b>Last Name: </b></td><td>'.$_POST['lname'].'</td></tr>';
$message .='<tr><td><b>Email: </b></td><td>'.$_POST['email'].'</td></tr>';
$message .='<tr><td><b>Company: </b></td><td>'.$_POST['company'].'</td></tr>';
$message .='</table>';

$elink = '[YOUR-WEBSITE-DOMAIN-AND-DIRECTORY]/download.php?token='.urlencode($encoded).'&attachment=vrpmac';
$message .= 'Thank you for your interest. Below is a one-day expired download link to the software.<br/>';
$message .= '<a href="'.$elink.'">'.'Download'.'</a><br>';
 
$message .='</body></html>';
 
$headers = "MIME-Version: 1.0" . "\r\n";
$headers .= "Content-type:text/html;charset=iso-8859-1" . "\r\n";

$headers .= 'From: <[YOUR-EMAIL-FROM-ACCOUNT]>' . "\r\n";
$headers .= 'Bcc: ' . $cc . "\r\n";

mail($to, $subject, $message, $headers);

echo msg(1,"registered.php?token=".urlencode($encoded).'&email='.urlencode($_POST['email']));


function msg($status,$txt)
{
 return '{"status":'.$status.',"txt":"'.$txt.'"}';
}
?>

The $token variable contains a token which makes the software download page generated valid for one day, to increase the security you may want to create more sophisticated token using encryption and random numbers.

The [YOUR-MAIL-SERVER-IP-ADDRESS] refers to your mail server address. The [YOUR-EMAIL-CC-ACCOUNT] refers to a cc account when the registration email is sent to the registered user. The [YOUR-WEBSITE-DOMAIN-AND-DIRECTORY] is the root directory which contains the download.php page (which is the page that provides the software download service), The [YOUR-EMAIL-FROM-ACCOUNT] is the from field in the email sent to the registered user.

The encryption.inc includes the encryption utility which prevents the user from deciphering the token. The source codes of the encryption.inc is shown below:

<?php

class Encryption {
    var $skey = '[YOUR-SECRET-KEY]';

    public  function safe_b64encode($string) {
        $data = base64_encode($string);
        $data = str_replace(array('+','/','='),array('-','_',''),$data);
        return $data;
    }

    public function safe_b64decode($string) {
        $data = str_replace(array('-','_'),array('+','/'),$string);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        return base64_decode($data);
    }

    public  function encode($value){ 
        if(!$value){return false;}
        $text = $value;
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->skey, $text, MCRYPT_MODE_ECB, $iv);
        return trim($this->safe_b64encode($crypttext)); 
    }

    public function decode($value){
        if(!$value){return false;}
        $crypttext = $this->safe_b64decode($value); 
        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $decrypttext = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $this->skey, $crypttext, MCRYPT_MODE_ECB, $iv);
        return trim($decrypttext);
    }
}

?>

The registered.php is a page displayed to the user after user submit the registration form. The page informs user and he has successfully registered (You can include the download link here if you like). The page checks whether the token is included in the url, if not or if the token is not valid, then the user is redirected to the registration.htm page. The source code of the registered.php is as below:

<?php
 require_once('encryption.inc');
 
 if(!isset($_GET['token']))
 {
  header( 'Location: registration.htm' ) ;
 }
 $message="dfjsl@ew".date('Ymd')."oqiej".date('Y')."!#@#@1".date('m')."2331";
 $converter = new Encryption;
 $encode=$_GET['token'];
 $decoded = $converter->decode($encode);  
 if(strcmp($decoded, $message) != 0)
 {
  header( 'Location: registration.htm' ) ;
 }
?>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>You've been registered!</title>
<link rel="stylesheet" type="text/css" href="reg.css">
</head>

<body>

<div class="registered">

<h1>The application link will be sent to your email account <?php echo $_GET['email']; ?></h1>
<br /><br /><br />

<br /><br /><br /><br />
<h2>Thank you for your registration. </h2>
</div>

</body>
</html>

Step 3: Create software download page
Below is the source code for the software download page, the download script first checks whether the token is valid or not, if not then redirect user to the registration page. Otherwise, it sends the software.

<?php


require_once('encryption.inc');
 
if(!isset($_GET['token']))
{
 header( 'Location: registration.htm' ) ;
}
$message="dfjsl@ew".date('Ymd')."oqiej".date('Y')."!#@#@1".date('m')."2331";
$converter = new Encryption;
$encode=$_GET['token'];
//$encoded = $converter->encode($message);
$decoded = $converter->decode($encode);  
if(strcmp($decoded, $message) != 0)
{
 header( 'Location: registration.htm' ) ;
}

if(isset($_GET['attachment']))
{
 if($_GET['attachment']=='vrpmac')
 { 
  $file = 'uyk0293fwie0.zip';
  if (file_exists($file)) 
  {
   header('Content-Description: File Transfer');
   header('Content-Type: application/octet-stream');
   header('Content-Disposition: attachment; filename=painter2.zip');
   header('Content-Transfer-Encoding: binary');
   header('Expires: 0');
   header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
   header('Pragma: public');
   header('Content-Length: ' . filesize($file));
   ob_clean();
   flush();
   readfile($file);
  }
 }
}

?>

Tuesday, July 16, 2013

Reading Xml in PHP using SimpleXML

suppose you have an xml file "sample.xml" on your server with the following content:

<samples>
<sample index="1" value="0.3" />
<sample index="2" value="0.332" />
<sample index="3" value="0.83" />
<sample index="4" value="0.23" />
</samples>

The following codes will transform the above xml file into a html table using SimpleXML:

<?php
echo "<table>";
$filepath="sample.xml";
$xml=simplexml_load_file($filepath);
foreach($xml->children() as $child)
{
$index=$child->attributes()->index;
        $val=$child->attributes()->value;
        echo "<tr><td>".$index."</td><td>".$val."</td></tr>";
}
echo "</table>";
?>

Monday, July 15, 2013

Yii Themes

To change the Yii default themes, download the theme from one of the Yii theme sites such as:

http://yii.themefactory.net/

After download, extract and copy the theme folder into the "themes" folder at your Yii application root folder. Suppose that the theme folder you name it as "MyNewTheme". Next in the protected/config/main.php, add or change the line:

'theme'=>"MyNewTheme",

within the returned array.


Resolve the PDO disabling issues for Yii on Godaddy hosting

My Yii application uses PDO for database access, which requires the server to have the PDO enabled. However, I am having some problem hosting my Yii application on GoDaddy, since hosting providers suych as GoDaddy disable PDO. After some searching, I found an alternative PHPPDO for Yii, which can be downloaded from:

http://www.yiiframework.com/extension/phppdo/

This extension allow you to use PHP-emulated PDO class on that hostings. The process of including PHPPDO for Yii application is very simple:

Step 1: download and extract the content of PHPPDO to protected/extensions of your Yii application
Step 2: in the protected/config/main.php, commented out the original db connection configuration and replaced with the PHPPDO one, just as in the following:

                /*
'db'=>array(
'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
),
// uncomment the following to use a MySQL database
'db'=>array(
'connectionString' => $ps_connectionString,
'emulatePrepare' => true,
'username' => $ps_dbusername,
'password' => $ps_dbpassword,
'charset' => 'utf8',
),*/
'db'=>array(
'class'=>'application.extensions.PHPPDO.CPdoDbConnection',
'pdoClass' => 'PHPPDO',
'connectionString' => $ps_connectionString,
'emulatePrepare' => true,
'username' => $ps_dbusername,
'password' => $ps_dbpassword,
'charset' => 'utf8',
),

500 (Internal Server Error) on GoDaddy when running Yii application

I have encountered and a problem with GoDaddy when running Yii application on the server. On the local machine, everything run smoothly for the Yii application. However, after I transfer the Yii application to Godaddy web hosting, I encountered the "500 (Internal Server Error)" when trying to visit the Yii application, no other information about the error is given. The error goes away after I set the permission for the Yii application's "assets" and "protected/runtime" to Read/Write.

During testing, i found another possible source of code errors that may cause the "500 (Internal Server Error)", which is when the developer does not specify the correct database host name when configure the protected/config/main.php

When the "500 (Internal Server Error)" happened on GoDaddy for Yii application, the best way to discover the error is to examine the protected/runtime/application.log, which may log the error.

Sunday, July 14, 2013

A simple shopping cart integration with eNETS and WorldPay using jQuery and PHP with database logging

Below is the demo code written in jQuery, PHP for a simple shopping cart which performs transaction with eNETS or WorldPay and log the records to the server:

http://www.4shared.com/zip/C-bgFisq/shopping_cart.html

The basic ideas is like this:  after the user enters the registration information and click "Checkout" button, the javascript on the client web browser will perform validation (e.g. check whether required fields are entered, whether the amount is greater than 0, etc). If the validation is correct, then the registration information will first post to the server as a record, which then returns a transaction reference number to the web browser. If the transaction reference number from the server is correctly returned, the javascript on the client web browser will post the form with the updated transaction reference number as well as the total amount to the enet (or worldpay), which then takes over the transaction.

  • The enets.html contains the web page and javascripts for working with eNETS, the javascript first post the form data to the log.php to be logged in the MySQL Server, and submit the form to eNETS gateway with the transaction reference received returned by the log.php
  • The worldpay.html contains the web page and javascript for working with WorldPay, the javascript first post the form data to the log.php to be logged in the MySQL Server, and submit the form to WorldPay gateway with the transaction reference received returned by the log.php
  • The log.php contains the PHP codes that logs that transaction data to the MySQL server, then returns the id of the last inserted transaction as the transaction reference to the jQuery post script which post the request.



Wednesday, July 10, 2013

Use cUrl in PHP to do posting to another web page

I have a registration form in which i need to validate user's input before send the data to third-party web page for transaction, and then returns back to the current page so that i can record the data and transaction into my database. To do this, i used cUrl which post the information collected from the user to the third-party  web page (as the third party web page requires post action). The way to do this is very simple as follows:

<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL,"http://www.third-party-site.com/transaction.php");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
            "postvar1=value1&postvar2=value2&postvar3=value3");

// in real life you should use something like:
// curl_setopt($ch, CURLOPT_POSTFIELDS, 
//          http_build_query(array('postvar1' => 'value1')));

// receive server response ...
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$server_output = curl_exec ($ch);

curl_close ($ch);

// further processing ....
if ($server_output == "OK") { ... } else { ... }

?>