How to configure Varnish cache on SSL.

Varnish is a HTTP reverse Proxy or HTTP accelerator. It is used to increase performance of the web application and reduce the time it takes to serve content to a user. The main technique it uses is caching responses from a web or application server in memory, so future requests for the same content can be served without having to retrieve it from the web server.

Actually Varnish stand between user request and Apache. When request come varnish check for caching if caching available for the request it server from varnish but if caching not available for that request then request goes to Apache and return to varnish and serve to the user. Varnish keeps the cache for this request so for the next time response served from varnish and it reduce the time to response of any request.

Varnish cache server.

How will be achieve this:

Actually we will keep Nginx server before varnish. So when request comes from HTTPS it will fall on Nginx, Nginx will call varnish if cache available to varnish it server from there. If there is no cache available to varnish request goes to Apache and process fall back.

Now the Varnish cache system will look like :

Got it but how to do this ?

There are some commands you need to run and some configuration (UBUNTU):

Install Varnish

 

sudo apt-get update
sudo apt-get install varnish

By default varnish runs on port 6081.

Configure Varnish

First, we will configure Varnish to use our LAMP.

The configuration file of vanish is located at /etc/varnish/default.vcl. Let’s edit it now:

sudo vi /etc/varnish/default.vcl

We need to change belwo lines:

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

And change the values of host and port match your LAMP server private IP address and listening port, respectively. Note that we are assuming that your web application is listening on its private IP address and port 80. If this is not the case, modify the configuration to match your needs:

backend default {
    .host = "LAMP_VPS_private_IP";
    .port = "80";
}

Like Apache, Varnish has also “grace mode” that, when enabled, instructs Varnish to serve a cached copy of requested pages if your web server backend goes down and becomes unavailable. Let’s enable that now.

sub vcl_backend_response {
    set beresp.ttl = 10s;
    set beresp.grace = 1h;
}

Save and exit the default.vcl file.

We will want to set Varnish to listen on the default HTTP port (80), so your users will be able to access your site without adding an unusual port number to your URL. This can be set in the /etc/default/varnish file. Let’s edit it now:

sudo vi /etc/default/varnish

We will various commented line. Find the following DAEMON_OPTS line (it should be uncommented already):

DAEMON_OPTS="-a :6081 \

The -a option is used to assign the address and port that Varnish will listen for requests on. Let’s change it to listen to the default HTTP port, port 80. After your modification, it should look like this:

DAEMON_OPTS="-a :80 \

Save and exit.

Now restart Varnish to put the changes into effect:

sudo service varnish restart

Now test it out with a web browser, by visiting your Varnish server by its public IP address, on port 80 (HTTP) this time:

Install Nginx

sudo apt-get install nginx

After installing Nginx, you will notice that it is not running. This is because it is configured to listen on port 80 by default, but Varnish is already using that port. This is fine because we want to listen on the default HTTPS port, port 443.

Let’s generate the SSL certificate that we will use.

Generate Self-signed SSL Certificate

On Varnish_VPS, create a directory where SSL certificate can be placed:

sudo mkdir /etc/nginx/ssl

Generate a self-signed, 2048-bit SSL key and certicate pair:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Make sure that you set common name to match your domain name. This particular certificate will expire in a year.

Configure Nginx

Open the default Nginx server block configuration for editing:

sudo vi /etc/nginx/sites-enabled/default

Delete everything in the file and replace it with the following (and change the server_name to match your domain name):

server {
        listen 443 ssl;

        server_name example.com;
        ssl_certificate /etc/nginx/ssl/nginx.crt;
        ssl_certificate_key /etc/nginx/ssl/nginx.key;

        location / {
            proxy_pass http://127.0.0.1:80;
            proxy_set_header X-Real-IP  $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
            proxy_set_header X-Forwarded-Port 443;
            proxy_set_header Host $host;
        }
}

Save and exit. The above configuration explained below in more detail:

  • ssl_certificate: specifies SSL certificate location
  • sslcertificatekey: specifies SSL key location
  • listen 443 ssl: configures Nginx to listen on port 443
  • server_name: specifies your server name, and should match the common name of your SSL certificate
  • proxy_pass http://127.0.0.1:80;: redirects traffic to Varnish (which is running on port 80 of 127.0.0.1 (i.e. localhost)

Now re-start the Nginx

sudo service nginx start

Magento2 Add/Create and Get custom customer attribute value

To create a custom attribute for customer in magento, firstly we need to add a file in setup folder of our module and then add the given code. Below we are adding ‘is_vendor’ attribute which has two option yes/no.

 setup\InstallData.php 
namespace W3solver\Helloworld\Setup;

use Magento\Customer\Setup\CustomerSetupFactory;
use Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
use Magento\Framework\Setup\InstallDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Customer\Model\Customer;

class InstallData implements InstallDataInterface {
    
    const IS_VENDOR = 'is_vendor';
    protected $customerSetupFactory;
    private $attributeSetFactory;

    public function __construct(
   CustomerSetupFactory $customerSetupFactory, AttributeSetFactory $attributeSetFactory
    ) {
        $this->customerSetupFactory = $customerSetupFactory;
        $this->attributeSetFactory = $attributeSetFactory;
    }

    public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) {
        $setup->startSetup();
        $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]);

        $customerEntity = $customerSetup->getEavConfig()->getEntityType('customer');
        $attributeSetId = $customerEntity->getDefaultAttributeSetId();

        $attributeSet = $this->attributeSetFactory->create();
        $attributeGroupId = $attributeSet->getDefaultGroupId($attributeSetId);

        $customerSetup->addAttribute(Customer::ENTITY, self::IS_VENDOR, [
            'type' => 'int',
            'label' => 'Is Vendor?',
            'input' => 'select',
            "source" => "W3solver\Helloworld\Model\Config\Source\CustomerYesNoOptions",
            'required' => false,
            'default' => '0',
            'visible' => true,
            'user_defined' => true,
            'sort_order' => 210,
            'position' => 210,
            'system' => false,
        ]);

        $is_vendor = $customerSetup->getEavConfig()->getAttribute(Customer::ENTITY, self::IS_VENDOR)
                ->addData([
            'attribute_set_id' => $attributeSetId,
            'attribute_group_id' => $attributeGroupId,
            'used_in_forms' => ['adminhtml_customer', 'checkout_register', 'customer_account_create', 'customer_account_edit', 'adminhtml_checkout'],
        ]);

        $is_vendor->save();
        $setup->endSetup();
    }
}

Above code will add a new attribute to customer, it can be checked on customer edit page in admin panel. So lets see how to get the value of this attribute. Firstly you need to inject customer repository interface in constructor

\Magento\Customer\Api\CustomerRepositoryInterface $customerRepositoryInterface

Now wherever you want to get the attribute value add the below code there:-

$customer = $this->customerRepositoryInterface->getById($customerId);
print_r($customer->getCustomAttribute('is_vendor')->getValue());


NOTE:-
Your code will only work for newly created customers because customer form has that attribute now and it will save its default value but already created customer did not have that attribute known to them, thus you need to write a small script to save all customer that were created previously and set whatever value you want for them. (this will be just one time process).

To set the value for the attribute to previous customer add the below code (try not to use object manager and inject those class through constructor:-

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $customerObj = $objectManager->create ('Magento\Customer\Model\Customer') ->getCollection ();
        foreach ($customerObj as $customerObjdata) {
            
            $customermodel = $objectManager->create ('Magento\Customer\Model\Customer');
            $customerData = $customermodel->getDataModel();
            $customerData->setId($customerObjdata->getData('entity_id'));
            $customerData->setCustomAttribute('is_vendor', 0);
            $customermodel->updateData($customerData);
            
            $customerResource = $objectManager->create ('\Magento\Customer\Model\ResourceModel\CustomerFactory')->create();
            $customerResource->saveAttribute($customermodel, 'is_vendor');
        }

Drop in your comments if you face any issue.

OOPS based interview question in PHP


1. What is Object Oriented Programming?

OOPS, a well-known and highly adopted programming language model which revolves around objects, which can have the data and functions. OOPs allows developer to maintain the code easily as it allows to keep similar type of functionality into classes, thus increase code reusability and add an extra layer of security, bind up functionality into a several smaller unit.


2. What are the principle of OOPS? Explain them?

The most frequently and a very popular interview questions for developer, OOPs majorly have 3-4 principles:-
Encapsulation
Wrapping up of data members and methods/function into a single unit i.e., in a class is known as encapsulation. It means hiding internal details of an object by using access specifier, thus adding a level of restriction to data members and function so that others objects cannot access them.

Abstraction
It hides the unnecessary data and show only the relevant information. We create abstract class and function in PHP to achieve abstraction.

Polymorphism
It means a same name function can have many forms or can behave differently in different situation. It is of two type; run time polymorphism i.e, overriding and compile tile polymorphism i.e, overloading. PHP does not have overloading similar to other OOPS languages. It achieve overloading by magic methods.

Inheritance
It provides code reusability, by allowing the child class to inherit the functions from parent class rather than writing it again and again. In PHP we extends classes by using extends keywords.

3. What is the purpose of a constructor?
A constructor is a magic method in PHP which is called automatically during initialization of an object. Constructors are used to assign default value or to perform any action which we want to do on a creation of an object. In PHP constructor is created in following way:-

function __construct(){}

Note: – Unlike other languages constructor in PHP are not created with the class name.

4. What is difference between abstract and interface?
Abstract class may or may not have abstract method, it can also have concrete method but in case of interface all methods are defined as abstract no concrete method is allowed. Interface is used to achieve multiple level inheritance.

5. What is Polymorphism? Does PHP support overloading?
Review answer of question 2 for this.

6. What is difference between abstraction and inheritance?
Both abstraction and encapsulation hides the information but in case of encapsulation it solves problem at implementation level, thus hiding the internal details of object i.e, how object does something, how its method and data member are interacting While abstraction solves problem at design level, it hides only the unwanted data and gives all relevant data such as outer look of a car, allowing you to use steering but did not know how it’s actually working.

7. What are magic methods?
Magic methods are special method in php that start with double underscore and convey special meaning to compiler, they are never called explicility. They are called implicility whenever needed. Such as __construct is always called automatically when an object of class is created.

8. How to call parent constructor in php?
parent::__construct() is used to call parent class constructor.

9. What are access modifiers?
Public, protected and private are the keywords used as access modifiers to set the visibility for functions and data members. Public members are accessible everywhere, protected are accessible only within the class itself or by inheriting class.

10. What is Scope Resolution Operator?
This operator refer to the scope of some blocks, and is used to access properties and method of classes. Mainly we use it to access static variables and method.

11. What is Static Keyword in PHP?
We make class properties and methods as static to access them without instantiating the class. They cannot be accessed with an instantiated class objects. Static keyword is also used for late static binding.

12. What is late static binding?
Late static binding is used to refer a class that was used at runtime, we use static keyword for this. Let’s understand it with an example:-

<?php
    class Car
    {
        public static function run()
        {
            return static::getName();
        }

        private static function getName()
        {
            return 'Car';
        }
    }

    class Toyota extends Car
    {
        public static function getName()
        {
            return 'Toyota';
        }
    }

    echo Car::run(); // Output: Car, Here we are calling run function by referring car class. And run function calls getName with static keyword that means class car run function will be used.
    echo Toyota::run(); // Output: Toyota, Here we are calling run function by referring toyota class. And run function calls getName with static keyword that means class toyota run function will be used.
?>

Thus in above example you can see that late static binding works by storing a class name in the last “non-forwarding call”.

13. What are Traits in PHP?
PHP only supports single inheritance i.e, a class can only inherit one other class. However, sometimes we need to inherit multiple classes.
Therefore PHP 5.4 introduces Traits, that reduce some limitations of single inheritance by allowing a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. Traits cannot be instantiated.
Below is the code explaining traits implementation:-

class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();

The above example will output:- Hello World!

14. What is Object Iteration?
It is possible to iterate through an object in PHP 5 through a list of items, for example by using a foreach statement. By default, all visible properties will be used for the iteration.

15. What is Final Keyword in PHP?
We use final keyword to prevents child classes from overriding a method or to prevent class itself from overriding.
For example,

class ABC{
   final function xyz(){}
}
xyz is set final which means it cannot we overridden in any other class.

16. Can we make a constructor as private?
Yes, we can, it is generally a common practice for Singleton Pattern. Making constructor as private ensures that there can be only one instance of a Class and provides a global access point to that instance.

17. What is serialization?
PHP provides an option for object serialization. We use serialize() function that returns a string containing a byte-stream representation of any value that can be stored in PHP and unserialize() function for vice-versa. For example:-

Suppose I have code:-
$serialized_data = serialize(array('Math', 'Language', 'Science'));
echo  $serialized_data;

Then the output of above code is a:3:{i:0;s:4:"Math";i:1;s:8:"Language";i:2;s:7:"Science";}

Magento 2 Programatically Change Category Attribute For All Store View

In this blog post we will change value of url_key for a category in Magento 2, similar step can be followed for changing any attribute in Magento 2.

Step 1

Firstly you need to inject category model factory in your constructor.

public function __construct(
    \Magento\Framework\View\Element\Template\Context $context,
    \Magento\Catalog\Model\CategoryFactory $categoryModelFactory,
   \Magento\Store\Model\StoreManagerInterface $storeManager
    ) {
        $this->_categoryModelFactory = $categoryModelFactory;
       $this->_storeManager = $storeManager;
        parent::__construct($context);
    }

Step 2

Now write the below code in your function

	$this->_categoryModelFactory = $this->_categoryModelFactory->create();
        $categoryCollection = $this->_categoryModelFactory->getCollection()->addAttributeToSelect('*');
        $stores = $this->getStores();
        
        foreach($categoryCollection as $collection){
            if($collection->getData('url_key')) {
                if($collection->getData('entity_id') == 20) {
                    foreach($stores as $store){
                    $this->_categoryModelFactory->load($collection->getData('entity_id'));
                    $this->_categoryModelFactory->setData('store_id', $store);
                    $this->_categoryModelFactory->setData('url_key', 'women');
                    $this->_categoryModelFactory->save(); 
                    }
                }
            }
        } 

Above we have used if statement and just changed url_key for a category with entity_id as 20, you can modify according to your requirement.
Also to get store list you need to write below function:-

public function getStores($withDefault = false, $codeKey = false)
    {
        $stores = [];
        // for 'all store view' in admin you need to seperately set id 0
        $stores[] = 0;
        foreach ($this->_storeManager->getStores() as $store) {
            
            $stores[] = $store->getStoreId();
        }
        
        return $stores;
    }

XLS to XML conversion using PHP

$lib =  libraries_load('PHPExcel'); //load PHPExcel library
  include $lib['library path'].'/IOFactory.php'; 
 //conveert xls to csv
            $objReader = PHPExcel_IOFactory::createReader('Excel5');
            $objPHPExcel = $objReader->load($url);
            $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'CSV');
            $path_to_file = $file_path."/".$file_name.'.csv';
            $objWriter->save($path_to_file);
            //convert csv to XML
            $csv = file($path_to_file);
              $xml_array = array();
                foreach($csv as $line){
                    $xml_key = explode(",", $line);
                    break;
                }
                $count =count($xml_key);
                $_key = array();
                for($i=0;$i< $count; $i++){
                 $_parsed_data = str_replace('"', '', $xml_key[$i]);
                 $_parsed_data = str_replace('(', '_', $_parsed_data);
                 $_parsed_data = str_replace(')', '_', $_parsed_data);
                 $_parsed_data = str_replace(' ', '_', $_parsed_data);
                 array_push($_key, strtolower($_parsed_data));
                 }
                 $xml_key = $_key;
                
            $data =array();
            foreach($csv as $line){
                 $line = str_replace('"', '', $line);
                 $line = str_replace('(', '_', $line);
                 $line = str_replace(')', '_', $line);
                $data[] = explode(",", $line);
            }
             $count = count($xml_key);
            for ($j = 0; $j < $count; $j++) {
               $text = $xml_key[$j];
               $data_new = $data_new."<".$text."></".$text.">";        
            }
            array_shift($data);
            foreach ($data as $key => $value) {
              $xml_new = $xml_new."<data>";
              foreach ($value as $new_key => $new_value) {
                $text = $xml_key[$new_key];
                  $new_value = str_replace('&', '&amp;', $new_value);
                  $parsed_field  = !empty(trim ($new_value)) ? trim($new_value) : ' ';
                 $xml_new = $xml_new."<".$text.">".$parsed_field."</".$text.">";   
                }
               $xml_new = $xml_new."</data>";
            }
            $xml_new = "<datas>".$xml_new."</datas>";
            $prepared_xml ='<?xml version="1.0"?>'.$xml_new;
            header('Content-disposition: attachment; filename='.$file_name.'.xml');
            header('Content-type: application/xml');
            echo $prepared_xml;

CSV to XML Conversion using PHP

CSV to XML Conversion using PHP.

$csv = file($url); //path to file
              $xml_array = array();
                foreach($csv as $line){
                    $xml_key = explode(",", $line);
                    break;
                }
            $data =array();
            foreach($csv as $line){
                $data[] = explode(",", $line);
            }
            $count = count($xml_key);
            for ($j = 0; $j < $count; $j++) {
               $text = strtolower(str_replace(' ', '_', $xml_key[$j]));
               $data_new = $data_new."<".$text."></".$text.">";        
            }
            array_shift($data);
            foreach ($data as $key => $value) {
              $xml_new = $xml_new."<data>";
              foreach ($value as $new_key => $new_value) {
                 $text = strtolower($xml_key[$new_key]);
                 $text =  strtolower(str_replace('(', '_', $text));
                 $text =  strtolower(str_replace(')', '_', $text));
                 $new_value = str_replace('&', '&amp;', $new_value);
                 $parsed_field  = !empty(trim ($new_value)) ? trim($new_value) : ' ';
                 $x = trim($new_value) ? 'yes' : 'no';
                 $xml_new = $xml_new."<".$text.">".$parsed_field."</".$text.">";    
                }
               $xml_new = $xml_new."</data>";
            }

            $xml_new = "<datas>".$xml_new."</datas>";
            $prepared_xml ='<?xml version="1.0"?>'.$xml_new;
            
            header('Content-disposition: attachment; filename='.$file_name.'.xml');
            header('Content-type: application/xml');
            echo $prepared_xml;

Xls to json conversion using PHP

Hey folks once again I am back with some useful code. Now we will see the code for xls to json conversion.

$lib =  @libraries_load('PHPExcel'); //load PHPExcel library
include $lib['library path'].'/IOFactory.php'; 
$objReader = PHPExcel_IOFactory::createReader('Excel5');
            $objPHPExcel = $objReader->load($url);
            $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'CSV');
            $path_to_file = $file_path."/".$file_name.'.csv';
            $objWriter->save($path_to_file);
           //  return drupal_goto($path_to_file); 
            $feed = $path_to_file;
            $keys = array();
            $newArray = array();
            $data = csvToArray($feed, ',');
            $count = count($data) - 1;
            //Use first row for names 
            $labels = array_shift($data);
            foreach ($labels as $label) {
                $keys[] = $label;
            }
           // Add Ids, just in case we want them later
            $keys[] = 'id';
            for ($i = 0; $i < $count; $i++) {
                $data[$i][] = $i;
            }
            for ($j = 0; $j < $count; $j++) {
                $d = array_combine($keys, $data[$j]);
                $newArray[$j] = $d;
            }
           $json_data = json_encode($newArray);
           header('Content-disposition: attachment; filename='.$file_name.'.json');
           header('Content-type: application/json');
          echo $json_data;

CSV to JSON conversion using PHP

CSV to json conversion.

         $feed = $url; // path to the csv file
            $keys = array();
            $newArray = array();
            $data = csvToArray($feed, ',');
            $count = count($data) - 1;
            //Use first row for names 
            $labels = array_shift($data);
            foreach ($labels as $label) {
                $keys[] = $label;
            }
           // Add Ids, just in case we want them later
            $keys[] = 'id';
            for ($i = 0; $i < $count; $i++) {
                $data[$i][] = $i;
            }
            for ($j = 0; $j < $count; $j++) {
                $d = array_combine($keys, $data[$j]);
                $newArray[$j] = $d;
            }
           $json_data = json_encode($newArray);
           header('Content-disposition: attachment; filename='.$file_name.'.json');
           header('Content-type: application/json');
          echo $json_data;

Magento 2 show different number of product for every category page

In this blogpost we will see how we can show different number of items or limit of a collection for every category page. For this you need to login to admin panel and follo following path:-

 Product > Category > Design > Layout xml update 

We have to update product_list_toolbar block and will set setDefaultListPerPage or setDefaultGridPerPage as per your page view type.

setDefaultListPerPage method will set limit for list page and setDefaultGridPerPage will set limit for grid page.

If you will try the below code:-

<referenceBlock name="product_list_toolbar">
        <action method="setDefaultListPerPage">
                 <argument name="limit" xsi:type="string">4</argument>
        </action>
 </referenceBlock>

There will be an issue that only allowed elements are referenceContainer, update, move. So the correct code that needs to be updated is

<referenceContainer name="content">
     <referenceBlock name="product_list_toolbar">
          <action method="setDefaultListPerPage">
             	 <argument name="limit" xsi:type="string">4</argument>
          </action>
    </referenceBlock>
</referenceContainer>

Change setting in admin configuration

Under configuration > catalog > catalog > storefront > Products per Page on List Allowed Values OR Products per Page on Grid Allowed Values set the limit whichever you are setting above. It is necessary else you will get default page value only.

How to create sub tab in Drupal 7

What is Sub tabs.

Sub tabs are a menu style which looks like tab.

How it Looks ???

Got It…. But how to implement this ??

Let us assume i have uploaded a .xls file and i want to give an option for user to download this file in different format. I will create separate sub tabs for this like below:

I am going to give an example to create sub-tab.

Create a module for this and call hook_menu() first and in the hook_menu() write below lines:

function hook_menu() {
$items['node/%yourmodule/download/csv'] = array(
    'title' => t('Download CSV'),
    'page callback' => 'change_formater',
    'page arguments' => array(1,2),
    'access arguments' => array(1),
    'file' => 'your_file.inc',
    'access callback'=>'check_downlodable_callback',
    'type' => MENU_LOCAL_TASK,
  );  
}

Description of every line:

  • In first line we are reserving a slug. Slug is nothing but a URL. On the click of this tab the URL will get called.
  • In the Second line we are giving title(lebel) for this sub tab. Wee always include any printable statement with t(); method.
  • In the Third line is a page callback. Page callback is nothing but a method name that you have written for your purpose.
  • Page argument: We are sending page argument to that method. It starts from 0index. so index we have download and on 2nd we have csv. So in your callback method change_formater() you will have have to receive two argument.
  • Wee are checking that this sub tab is only show on the selected content type. SO we have passed access argument =array (1). in our access callback we will get entire node. So we can get node type from there and bind a condition. So that only selected content type will have this this subtab.
  • Next is file so Best practice is to create your .inc file and keep your logic in this file. Same as keep your all download conversion logic in this .inc file.
  • access callback: Here we define a method name. In this method we will check the accessibility of this tab.
  • Type is MENU_LOCAL_TASK. It will generate a subtab.

Here is the access callback method so that you can understand it more clear.

function check_downlodable_callback($node){
  if ($node->type=='resource')
    return true;
  else
    return false;
}

As i have said that passing 1 in array for access argument. We will get the entire node in method. I have checked that if node type is resource only then this subtab will display.

Hope it will help You. Will share some more help full stuff.