Blog

Cyanogenmod Updater crashes when using Nightly builts

In case you are trying to update Cyanogenmod the a current Nightly built (e.g. Nightly Cm-11-20150201) chances are that the CM updater crashes before even rebooting to the actual updating process. This problem has been confirmed by PsychoI3oy on the CM forum:

Yeah, we’ve been getting a lot of crashes in the backend from cmupdater. It has been fixed and we’re doing a special re-run of cm11 nightlies starting today that will have this fix. You’ll still have to manually install this update but after that it should be fine. For anyone else having this issue: please stop hitting report on the crash button. We have plenty of reports. Thanks

Solution

The solution is pretty simple: Just do a manual update by powering up your device while pressing Home + Volume Up + Power simulateously. Of course make sure to download a recent nightly version using CM updater. As stated in various bug reports this issue will be fixed once a manual update was executed. Personally, I did not experience problems with updates using the regular CM updater approach after executing the process manually as described above.

Automatically clean product texts in Magento

So someone copied text from a PDF document and pasted it into the Magento product description (or short description) text field. Unfortunately, the copied text included non-printable control characters in the Unicode range from \x00—\x1F and \x80-\x9f (e.g. DEL, NUL, VT, etc.) thus breaking other extensions from functioning properly, or prohibiting your data export to work at all. 

Clean product texts extensions to the rescue

The Clean product texts extension helps you to automatically clean your product texts (description and short description) by removing unwanted (invisible) control characters that might cause problems with other extensions or when exporting products. Oftentimes, unwanted characters are copied into product descriptions when copying texts from PDF documents. Since these control characters are not displayed by browsers they cannot be removed manually from Magento’s editor. This extension will check your product texts and automatically remove unwanted characters. Thus, your employees can still copy texts from e.g. PDFs directly into Magento – this extension will take care of removing unwanted characters when saving products.

Simulate Product Cleaning

Furthermore, you can also simulate the process of cleaning product texts by activating the corresponding option in the configuration under General / Simulate.

Log File

In addition this extension enabled you to logs messages to a custom log file that can be specified in the configuration options to your log directory under General / Log File. So you have the option to easily track events handled by this extension and check for possible problems. Feel free to check out the Clean product texts extension on Magento Connect.

Overloading constructors and functions in PHP

Since I was recently asked whether it’s possible to overload constructors in PHP, or functions in general, here is the quick answer: No, not in the common sense of “overloading”, i.e. creating multiple versions of the same function name with different implementations and arguments. Thus, the following is not possible by default in PHP:

class MyClass {
  /**
   * Default constructor.
   */
  public function __construct() {
    ...
  }

  /**
   * NOT POSSIBLE: Overloaded constructor with additional argument(s).
   */
  public function __construct($someArgument) {
    ...
  }
}

Pattern-based Overloading in PHP

So how is it possible to achieve overloading of constructors and functions in general? Well, we can make use of the factory pattern and add fluent interfaces:

class MyClass {
  /**
   * Hide default constructor.
   */
  private function __construct() {
    ...
  }

  /**
   * Instead of overloaded constructor use factory pattern and fluent interfaces.
   */
  public static function create($someArg) {
    $instance = new self();
    ...
    return $instance; // keep it fluent and return instance
  }
}

func_get_args to the rescue

Ok, but this is not really overloading functions per-se. So, are there any alternatives to this approach? Yes, there are some, e.g. use func_get_args in the default constructor:

public function __construct()  {
   $arguments = func_get_args(); // get variable number of arguments
   ...

But using this approach chances are that you’ll end up with spaghetti code in order to check the arguments specified (amount, type, etc.). Thus, using the factory pattern in combination with fluent interfaces will keep your code clean and easily documentable.

Avoid recursive calls in Magento observer classes

Since I was recently asked how to avoid recursive calls in Magento observer classes when for instance calling save() in an xxx_save_after event observer: Simply use an internal processing flag.

class My_Products_Model_Observer {

  /** @var boolean flag to signal successful processing of current model entity */
  private $_isProcessed = false;

  /**
   * Handle catalog_product_save_after event.
   * @param Varien_Event_Observer $observer
   */
  public function catalog_product_save_after(Varien_Event_Observer $observer) {
    try {
      $product = $observer->getEvent()->getProduct();

      // do some processing...

      if(!$_isProcessed) {
        $this->_isProcessed = true; // avoid recursion
        $product->save();
      }
    } catch (Exception $e) {
      Mage::log($e->getMessage()); // do some logging
    }
  }
}

That’s it – Sometimes things can be very simple 😉

Fixing Magento error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

This is just a quick fix post in case you are experiencing the error

error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure

Magento SSLv3 Connect Error Check file downloader/lib/Mage/HTTP/Client/Curl.php for a proper secure transportation protocol supported by Magento Connect (SSLv3 vs. TLSv1):

$this->curlOption(CURLOPT_URL, $uri);
$this->curlOption(CURLOPT_SSL_VERIFYPEER, FALSE);
$this->curlOption(CURLOPT_SSL_VERIFYHOST, 2);

Solution

In order to overcome this error simply add the cUrl option TLSV1:

$this->curlOption(CURLOPT_SSL_CIPHER_LIST, 'TLSv1');

Background info

Magento Connect (finally) canceled support for SSLv3. Thus, when Magento downloader tries to communicate with Magento Connect server it fails due to incompatible security protocols. You can easily fix this error by specifying TLSv1 as alternative security protocol.

Enabling Cross-Origin Resource Sharing CORS for PHP

This post is an addition to Enabling Cross-Origin Resource Sharing CORS for Apache to show you how to enable Cross-Origin Resource Sharing CORS for PHP. Thus, in case you don’t have access to the .htaccess you can simply enable CORS for PHP using the following steps.

Setting required headers using PHP

As explained in Enabling Cross-Origin Resource Sharing CORS for Apache you need to make sure that responses to cross-domain requests to your server (e.g. through Ajax requests using jQuery) need to include a set of required headers to be accepted by the client browser. These are

  1. Access-Control-Allow-Origin
  2. Access-Control-Allow-Methods
  3. Access-Control-Max-Age
  4. Access-Control-Allow-Headers

Make sure that Access-Control-Allow-Origin is set a domain value actually allowed by your server. In theory you could use ‘*‘ as well, but some browsers (e.g. Firefox) will simply ignore it and CORS will not work.

PHP code to enable CORS

The following snippet should give you a quick overview about the required HTTP headers to set for CORS to work.

First, it defines a list of allowed origin domains based on regular expressions. This list will be checked against $_SERVER[‘HTTP_ORIGIN’], i.e. the Origin header specified in the client request. If one origin entry from the list matches the required CORS headers will be set. This setup also takes care of the CORS pre-flight request.

// array holding allowed Origin domains
$allowedOrigins = array(
  '(http(s)://)?(www\.)?my\-domain\.com'
);

if (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['HTTP_ORIGIN'] != '') {
  foreach ($allowedOrigins as $allowedOrigin) {
    if (preg_match('#' . $allowedOrigin . '#', $_SERVER['HTTP_ORIGIN'])) {
      header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
      header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
      header('Access-Control-Max-Age: 1000');
      header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With');
      break;
    }
  }
}

Managing Magento Invoice and Billing Ids

In case you need to change the invoice and billing IDs in Magento only a few things need to be done. First, make sure you understand the logic how these IDs are assembled so you don’t mess with existing numbers 😉

Magento Invoice and Billing ID Schema

Have a look at the eav_entity_type table and search for the entity_type_codes

  • order
  • invoice
  • creditmemo
  • shipment

Magento Entity Type IDs Note the corresponding entity_type_id column which will be used by the eav_entity_store table: Magento Order ID and Invoice ID Based on the triplet

  • store_id
  • entity_type_id
  • increment_prefix

you can set unique billing and invoice IDs for your stores.

Advanced settings

In addition to the increment prefix you can also set advanced features such as

  • increment_pad_length
  • increment_pad_char

Magento advanced billing and invoice ID settings Thus, in case you want to set custom padding characters or change the default ID length simply update to corresponding value in the table eav_entity_type.

Changing Billing or Invoice IDs

In case you want to change your billing or invoice IDs make sure that your new ID schema does not conflict with an existing one (and as always make a backup of your database). To update the IDs alter the corresponding increment_prefix and generate all artefacts at least once so that Magento sets the initial IDs for your new ID schema.

Automatically copy images from parent configurable product to variants in Magento

By default Magento does not copy images from parent configurable products to their child variants, i.e. associated products. So you need to manually set images for child products once they are associated with the parent configurable product, which can be rather time consuming and (let’s face it) annoying if you deal with a broader range of product variants. So, wouldn’t it be nice if Magento automatically copied images from parent products to their child product variants? Yes! Luckily, this can be achieved with the following extension.

Extension to the rescue

The Magento extension called Automatic Image assignment for configurable product variants takes care of automatically assigning required image types from parent configurable products to their associated child product variants based on the base image from the parent product once it is saved (hint: see shell script for bulk updates below). Thus, once you save the parent configurable product it checks its child products for a custom list of required image types you can set via the extension configuration. Possible required image types include

  • Base image
  • Small image
  • Thumbnail

So, you are able to set individual image types to be copied to child products based on the base image from the parent configurable product. For instance, selecting small image and thumbnail as required image types will copy the base image from the parent product and set them for the child products in case these image types do not yet exist.

Simulate Image Assignment

Since your products are your treasure the extension offers the options to simulate the process of automatically copying and assigning images. So, instead of altering products in the database the extension will log all required actions in the custom log file specified (yes, the extension offers a custom log file, see below for more information).

Shell script for bulk update

Since the extension is primarily designed as event observer for saving parent configurable products an additional shell script is included in the package. This script will either process all configurable products and check their child products for the required image types set in the configuration or limit the list of products to be checked by an additional product-IDs parameter.

Custom log file

Finally, in order to track the extension’s step you can specify a custom log file that will enable you to easily monitor actions carried out by the extension. Thus, you can easily simulate a bulk update and track events through the log file.

Download the extension

Feel free to download the extension from Magento Connect published by Both Interact.

Alternatively, you can download the latest version 1.6.3 here: BothInteract_ConfigurableProductVariantsImageAssignment-1.6.3.

PHP Mailing List – Version 2.0.0 Released

Today, version 2.0.0 of PHP Mailing List was released. Due to numerous inquiries support for Google Analytics tracking code was added. You can simple set it via the supplied config file. Also, protocol prefixes in the template files have been removed for auto-detection.

Feel free to download the latest version via GitHub.

UPDATE: In version 2.2.0 Google Analytics event tracking has been added.

Switching WordPress to https only

As you might have seen I’ve switched this site to https only. The steps involved in switching WordPress to https only are pretty simple.

Set Site URL

First, make sure to set the proper https site URLs. You find these options under Settings » General: Wordpress set site URL to https

Redirect non-https traffic

Second, make sure to redirect all non-https requests to https-only in your .htaccess file. In the example below I’ve included an automatic redirect to the www subdomain for the SSL certificate. You can safely ignore this step in case you have a different setup:

 
RewriteEngine On
RewriteBase /

RewriteCond %{HTTP_HOST} !^www.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Update media URLs

Afterwards, you (probably) need to update the URLs of your referenced media files in your blog posts/pages. Do so by issuing the following command (of course replace with your proper domain):

UPDATE wp_posts SET post_content = 
replace(post_content, 'http://www.YOUR-DOMAIN.com', 'https://www.YOUR-DOMAIN.com');

Update template and plugins

Finally, you need to make sure that your theme and respective plugins do not statically reference any http-only files, e.g. fonts.google, etc. For instance, for the tiga-theme that this site’s is derived from you need to overload the Google fonts URL set by enqueue.php (replace http:// with // only):

wp_enqueue_style( 'tiga-font', 
'//fonts.googleapis.com/css?family=Francois+One|Open+Sans:400italic,400,700', 
null, TIGA_VERSION, 'all' );

That’s it 😉

Handling cookies in Magento with JavaScript

In order to handle cookies in Magento refer to /js/mage/cookies.js. The functions for getting, settings and clearing cookies are:

  • Mage.Cookies.set
  • Mage.Cookies.get
  • Mage.Cookies.clear

Below you find the corresponding JavaScript functions from cookies.js:

Mage.Cookies.set = function(name, value) {
     var argv = arguments;
     var argc = arguments.length;
     var expires = (argc > 2) ? argv[2] : Mage.Cookies.expires;
     var path = (argc > 3) ? argv[3] : Mage.Cookies.path;
     var domain = (argc > 4) ? argv[4] : Mage.Cookies.domain;
     var secure = (argc > 5) ? argv[5] : Mage.Cookies.secure;
     document.cookie = name + "=" + escape (value) +
       ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +
       ((path == null) ? "" : ("; path=" + path)) +
       ((domain == null) ? "" : ("; domain=" + domain)) +
       ((secure == true) ? "; secure" : "");
};

Mage.Cookies.get = function(name){
    var arg = name + "=";
    var alen = arg.length;
    var clen = document.cookie.length;
    var i = 0;
    var j = 0;
    while(i < clen){
        j = i + alen;
        if (document.cookie.substring(i, j) == arg)
            return Mage.Cookies.getCookieVal(j);
        i = document.cookie.indexOf(" ", i) + 1;
        if(i == 0)
            break;
    }
    return null;
};

Mage.Cookies.clear = function(name) {
  if(Mage.Cookies.get(name)){
    document.cookie = name + "=" +
    "; expires=Thu, 01-Jan-70 00:00:01 GMT";
  }
};

Generic cookie clear function

In case you are searching for a simple, generic function to clear (Magento) session cookies you might want to use the following snippet ($vhost is the current VHost determined by PHP’s globals, e.g. www.yoursite.com):

function clearCookie(name, domain, path) {
  var domain = domain || document.domain;
  var path = path || "/";
  console.debug(name + "=; expires=" + +new Date + "; domain=" + domain + "; path=" + path);
  document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;domain=" + domain + ";path=" + path;
}

try {
  console.debug('Removing session cookie...');
  clearCookie('frontend', '<!--?php echo $vhost; ?-->', '/');
  console.debug('Removed cookie');
} catch (Error) {
  console.error('Failed to remove cookie');
}

Linking JIRA to GitHub to streamline agile workflow

In order to automatically track and link the progress of your JIRA issues based on your developers’ commits in your Github repositories make sure to checkout the JIRA DVCS connector addon.

It only takes a few simple steps to link your JIRA projects to your GitHub repositories to streamline your agile workflow, as shown below. First, you’ll need to register a new application for your main GitHub account, in order to generate OAuth tokens required to link JIRA to GitHub:

Generate OAuth tokens in GitHub

Choose JIRA DVCS for the application name and your full base URL of your JIRA cloud-based setup for Homepage URL and Authorization callback URL:

Configuring DVCS connector URL in GitHub Once you’ve registered your new application you will get the OAuth tokens (client ID and client secret) required by the JIRA DVCS connector:

Configure DVCS connector using OAuth tokens in GitHub

Now that you have your OAuth tokens it’s time to setup the JIRA DVCS connector. Thus, open the Administration > Source Control > DVCS Accounts tab in JIRA and select Link BitBucket or GitHub account:

Link JIRA DVCS to GitHub using OAuth tokens

There you’ll need to enter the OAuth tokens generated in GitHub:

Link JIRA DVCS to GitHub using OAuth tokens

Feel free to select Auto Link New Repositories and Enable Smart Commits when needed. Once you’ve added the tokens you get a list of your authorized GitHub repositories (public and private, depending on the permissions chosen for the GitHub application) that are now available to JIRA:

Checking available GitHub repositories from within JIRA DVCS

 

Final Step

The last thing to do is to check that your developers have the proper rights for the View Development Tools permission:

Setting View Development Tools permission in GitHub

Now that everything is set up properly remind your developers to use the JIRA issue ID in the commit messages so that the JIRA DVCS connector is able to automatically assign commits to your issues.

Further reading is available here: Streamlining your development with JIRA.

Magento M2E Pro Newsletter Subscription Extension released

Note: The terms and conditions for using this extension are currently being reviewed to further conform to eBay’s terms and conditions. Thus, this extension is temporarily disabled on Magento Connect until the approval process is completed.

Both Interact today released the M2E Pro Newsletter Subscription extension. This extension takes care of automatically subscribing your eBay customers to your Magento newsletter. Future releases will give you further options to customize the settings, such as

  1. newsletter confirmation options
  2. e-mail blacklists
  3. and much more

The extension is free of charge – feedback is always welcome!

Configure robots.txt for Realurl in TYPO3

In order to configure robots.txt for the Realurl extension in TYPO3 you need to set two things:

  1. Add filename for page type 201 in realurl_config.php
  2. Add some TypoScript to process robots generation

Add filename for page type in realurl_config.php

$TYPO3_CONF_VARS['EXTCONF']['realurl']['_DEFAULT'] = array(
  ...
  // configure filenames for different pagetypes
    'fileName' => array(
        'defaultToHTMLsuffixOnPrev' => 0,
        'index' => array(
            'print.html' => array(
                'keyValues' => array(
                    'type' => 98,
                ),
            ),
            ...
            // add robots.txt page type
            'robots.txt' => array(
                'keyValues' => array(
                    'type' => 201
                )
            )
        ),
  ...

Add TypoScript to process robots.txt generation

robots = PAGE
robots {
  typeNum = 201
  config {
    disableAllHeaderCode = 1
    additionalHeaders = Content-type:text/plain
  }
  10 = TEXT
  10 {
    wrap (
User-Agent: *
Allow: /                #allow everything by default
Disallow: /fileadmin/templates     #then add restrictions
Disallow: /typo3/        
Disallow: /t3lib/        
Disallow: /typo3conf/    
Disallow: /typo3temp/    
Disallow: /*?id=*        

User-agent: googlebot  # Google specific settings
Disallow: /*?tx_indexedsearch

Sitemap: /?eID=dd_googlesitemap # finally add some sitemap
    )
} 

Be sure to flush the cache and you are all set!

Generate hreflang alternate tags in TYPO3

Here is a quick TypoScript snippet that generates hreflang alternate tags in TYPO3. Take note of the following parameters:

  • special.value: set IDs of languages available, e.g. 0
  • stdWrap.cObject.value: specify the locale corresponding to special.value, e.g. de-AT
  • stdWrap.typolink.additionalParams: specify the special.value values for each locale set

TypoScript code to generate hreflang alternate tags

Here’s the snippet for a couple of exemplary locales:

page.headerData.100 = HMENU
page.headerData.100 {
  special = language
  special.value = 0,1,2,3,4
  1 = TMENU
  1 {
    NO = 1
    NO {
      stdWrap.cObject = TEXT
      stdWrap.cObject {
        value = de-AT || en || it-IT || fr-FR || sl-SI
      }
      linkWrap = 
        stdWrap.typolink.parameter.data = page:uid
        stdWrap.typolink.additionalParams = &L=0 || &L=1 || &L=2 || &L=3 || &L=4
        stdWrap.typolink.returnLast = url
      }
    }
  }
}

Snippet Output

The snippet above produces the following output:

<link rel="alternate" hreflang="de-AT" href="http://www.somedomain.at/at-page" />
<link rel="alternate" hreflang="en" href="http://www.somedomain.com/en-page" /> 
<link rel="alternate" hreflang="it-IT" href="http://www.somedomain.it/it-page" /> 
<link rel="alternate" hreflang="fr-FR" href="http://www.somedomain.fr/fr-page" /> 
<link rel="alternate" hreflang="sl-SI" href="http://www.somedomain.si/si-page" />

That’s it!