Jul 25 2019
Jul 25

Submitted by karthikkumardk on Thursday, 25 July 2019 - 15:29:44 IST

file_scan_directory is deprecated and has been moved to the file_system service.

Before:

$files = file_scan_directory($directory);

After

if (is_dir($directory)) {
  $files = \Drupal::service('file_system')->scanDirectory($directory);
}

When possible, you should inject the FileSystemInterface into your constructor.

Original source - https://www.drupal.org/node/3038437

Jul 19 2019
Jul 19

Redis is an open-source, networked, in-memory, key-value data store that can be used as a drop-in caching backend for your Drupal

Add the Redis module from Drupal.org. You can install and enable the module from the command line.

Edit sites/default/settings.php to add the Redis cache configuration. These are the mandatory, required Redis configurations for every site.

// Use Redis for caching.
$conf['redis_client_interface'] = 'PhpRedis';
// Point Drupal to the location of the Redis plugin.
$conf['cache_backends'][] = 'sites/all/modules/redis/redis.autoload.inc';
$conf['cache_default_class'] = 'Redis_CacheCompressed';
$conf['cache_prefix'] = array('default' => 'pantheon-redis');
// Do not use Redis for cache_form (no performance difference).
$conf['cache_class_cache_form'] = 'DrupalDatabaseCache';
// Use Redis for Drupal locks (semaphore).
$conf['lock_inc'] = 'sites/all/modules/redis/redis.lock.inc';

Enable the module via from /admin/modules

Verify Redis is enabled by going to the Dashboard and clicking "Connection Info". If you see the Redis cache connection string, Redis is enabled

Visit /admin/config/development/performance/redis and open Connection Information to verify the connection.

And once the Redis server is connected, one could use the PhpRedis functions to set the key & value pairs on Redis as seen below

function _get_value_redis_cache($key) {
    try {
        $redis = Redis_Client::getClient();
        return $redis->get($key);
    }
    catch (Exception $exception) {
        watchdog('redis_cache', t('Error, while getting the value from redis cache.'), custom_log(array($key, $redis)), WATCHDOG_ERROR);
    }
}

function _set_value_redis_cache($key, $value) {
    try {
        $redis = Redis_Client::getClient();
        $redis->set($key, $value);
        $now = time();
        $redis->expireAt($key, $now + 900);
        $redis->save();
    }
    catch (Exception $exception) {
        watchdog('redis_cache', t('Error, while setting the value from redis cache.'), custom_log(array($key, $value, $redis)), WATCHDOG_ERROR);
    }
}

Once these generic functions are ready, one could utlize this functions for setting and getting the values based on the keys as seen below

$key = "_get_tmp_value_from_redis";
$tmp = _get_value_redis_cache($key);
if (empty($tmp)) {
    $tmp = get_actual_value_from_db();
    _set_value_redis_cache($key, $tmp);
    return $tmp;
}
else {
    return $tmp;
}

cheers :)

Jul 17 2019
Jul 17

The Migrate Drupal UI module provides a web browser user interface for upgrading from Drupal 6 / 7 to Drupal 8. There is a pre-upgrade analysis which displays a list of legacy modules that will be upgraded and will not be upgraded. Included in those that will be upgraded are modules that do not need an upgrade, such as the Help module. In order for this analysis to be correct, some Drupal 8 modules must provide information in a MODULE_NAME.migrate_drupal.yml file in the module's migrations/state directory.

This applies to Drupal 8 modules that:

  • Provide migrations from a Drupal 6 or Drupal 7 module, or
  • Intend to provide those migrations in the future, or
  • Are a successor to a Drupal 6 or Drupal 7 module and want to communicate that no migration is needed.

This does not apply to modules that are brand new in Drupal 8 and have nothing to communicate about any Drupal 6 or Drupal 7 modules.

Syntax

finished:
  6:
    source_module: destination_module
    source_module_2: destination_module
    source_module_3:
    - destination_module
    - destination_module_2

  7:
    source_module: destination_module
    source_module_3:
    - destination_module
    - destination_module_2

not_finished:
  7:
    source_module_2: destination_module

As can be seen above, the data in migrations/state/MODULE_NAME.migrate_drupal.yml consists of migration sets where each set is a source module for a legacy Drupal version (6 or 7), and one or more destination modules for the current Drupal version (8). The source module and destination modules correspond to the source_module and destination_module definitions in the migrations. And each set can be declared either 'finished' or 'not_finished'. For a set to be "finished", all of the migrations for the set must exist. If a module maintainer knows that they have not yet provided all of the migrations that are needed from a given source module to one or more destination modules, then they should declare that set as "not_finished".

Merging state across provider modules, source modules, and destination modules

Each module's migrations/state/MODULE_NAME.migrate_drupal.yml file defines the state of the migrations that are provided (or intended to be provided in the future) by that module. In most cases, destination modules are the sole providers of migrations to themselves. For example, the dblog module is the sole module that provides migrations from earlier versions of itself to itself. In some cases, modules provide migrations for other destination modules. For example, the Content Translation module provides migrations from earlier versions of the Statistics module to the current version of the Statistics module. This is in addition to the migrations provided by the Statistics module itself.

The Migrate Drupal module considers a source module / destination module pair as not finished if there is any provider that declares it as not finished. For example, in the above example, if the Content Translation module in its .migrate_drupal.yml were to declare that statistics: statistics were "not_finished", then Migrate Drupal considers that pair to be not finished, even if the Statistics module itself is finished with the migrations that it intends to provide.

Similarly, a given source module is considered not finished overall, if there exists at least one destination module for which it is declared as not finished. For example, there are migrations from the Drupal 6/7 Menu module to several Drupal 8 destination modules (System, Menu UI, and Custom Menu Links). If any one of those pairs (e.g., menu: system, menu: menu_ui, or menu: menu_link_content) were declared as not finished (by any provider module), then on the Migrate Drupal UI pre-upgrade review screen, the Menu module would be listed as "will not be upgraded".

Usage

If the Drupal 8 module is not providing migrations, now or in the future, for its legacy version then create a migrate_drupal.yml. Declare a finished migration for each legacy Drupal version. See scenario 1 below.

If the Drupal 8 module is or will be providing migrations for a legacy module then create a migrate_drupal.yml file. For each source_module:destination_module pair used by the migrations in your module do the following for Drupal 6 and Drupal 7.

  • If the migrations for the pair are complete add a line in the "finished" array for the relevant Drupal version.
  • If at least one migration for a pair exists but the pair is not finished add an entry to "not_finished" for the relevant Drupal version.
  • If the migrations needed for the pair do not exist then add a line in the "not_finished" array for the relevant Drupal versions.

Examples

Scenario 1. A successor to a legacy module that for any reason will not be providing a migration. Let's use Pirate as the example. Currently, if Pirate is enabled on the legacy site it will be displayed as will not be upgraded when it should be listed as will be upgraded. To make that happen simply declare a migration set with pirate as the source module and destination module as finished.

finished:
  6:
     pirate: pirate
  7:
     pirate: pirate

Scenario 2. The legacy version of your module has content and configuration that needs to be upgraded. Your module provides two migrations with the same source_module:destination_module pair for both Drupal 6 and Drupal 7 and all migrations are finished.

finished:
   6:
     google_analytics: google_analytics
   7:
     google_analytics: google_analytics

Scenario 3. Your module provides migrations. The Drupal 6 version is complete but the Drupal 7 is not. Note there may be zero or more migrations for Drupal 7 in your module but more are needed for it to be complete.

 finished:
    6:
      google_analytics: google_analytics
  not_finished:
    7:
      google_analytics: google_analytics

Scenario 4. Your module provides migrations for other modules with many pairs, such as Commerce Migrate Module.

finished:
    6:
      node: commerce_product
      system: commerce_store
    7:
      node: commerce_product
      commerce_product: commerce_product
      system: commerce_store
  not_finished:
    6:
      uc_orders: commerce_order
    7:
      uc_orders: commerce_order
      commerce_order: commerce_order

Scenario 5. Your module provides a migrate field plugin for a legacy field, such as Address Module.

  finished:
    6:
      adressfield: address
    7:
      adressfield: address

Scenario 6. Menu, JQuery UI, Blog, Color and many other modules moved directly into Core. These are denoted as 'core' for the destination and are treated specially. They are marked as finished since these do not have an upgrade path and site upgraders do not need to look for an equivalent project to install in Drupal 8.

finished:
  6:
    blog: core
    blogapi: core
    calendarsignup: core
    color: color
  7:
    blog: core
    bulk_export: core
    contextual: core
    ctools: core

Cheers :)

Jun 26 2019
Jun 26

How to Set, Get and Invalidate the caches per user in Drupal 7, this blog article will explain a brief of how to do such implementation on Drupal using the default drupal cache functions.

Here, we go with the steps

  • Initially, create the custom functions for Get, Set and Invalidate the caches per user.
  • Here, cache id per user is pretty important, where user id or user email id will used as part of cache id.
  • And these functions should be used as when required for caching the page.
  • Their will be cases like, Caches should be Invalidated on some actions for that particular user. These can be covered with these below functions.

Here's the functions which are used to Get, Set and Invalidate caches.

<?php

function _get_cache($cache_id) {
    $cache = cache_get($cache_id);
    if (isset($cache_id) && REQUEST_TIME < $cache->expire) {
        return $cache->data;
    }
    else {
        return NULL;
    }
}

function _set_cache($cache_id, $data) {
    cache_set($cache_id, $data, 'cache', REQUEST_TIME + (60 * 60));
}

function _invalidate_cache($cache_id) {
    $cache = cache_get($cache_id);
    if (isset($cache) && !empty($cache)) {
        cache_clear_all($cache->cid, 'cache');
    }
}

Here's the function where we Set the cache on page load, if at all already cache doesn't exist for this cache id.

function sample() {
    global $user;
    $cache_id = $user->uid . "_sample";
    $cache_data = _get_cache($cache_id);
    if ($cache_data == NULL) {
        $cache_data = array();
        // Here processed data should be cached
        $data = getData();
        $cache_data['data'] = $data;
        _set_cache($cache_id, $cache_data);
    }
    return $cache_data;
}

Here's the function used to Invalidate the caches, on some particular actions of the particular user.

$cache_id = $user->id . "_sample";
_invalidate_cache($cache_id);

Advantages of having the caches enabled for few pages, The page load time will be reduced..

Cheers :)

Jun 24 2019
Jun 24

Store Drupal logs on Amazon S3 via hook_watchdog, so that you can get rid of heavy logs on your drupal database and can later read from the S3.

For this todo on Drupal

  • You should use the "hook_watchdog" hook, where this hook allows modules to route log events to custom destinations.
  • In our case, our custom destination will be S3.
  • Initially we need to get the access to AWS and appropriate S3 bucket.
  • Store the connection configuration details of S3 buckets in the Drupal.
  • In the hook_watchdog, read the S3 Auth configs.
  • Create a connection to AWS S3, on success it return back with the S3 object.
  • Check if any buckets exist to write the logs, of not you should create bucket on S3 for logs.
  • Next, Create a log directory and log file, populate it with the data came on hook_watchdog.
  • Next, Write to the S3 bucket with parameters which "putObject" expects.
  • Next, Remove the log directory & file which is created in the process.
  • Check the S3 bucket via S3 UI, you could see the logs

Here's the piece of code, via we log to S3.

watchdog(
    'module_2',
    t('Info: Successfully completed.'),
    array($data),
    WATCHDOG_INFO
);
watchdog(
    'module_3',
    t('Error: Issue while processing.'),
    array($exception, $data),
    WATCHDOG_ERROR
);

Here, the piece of code which helps to connect & write log's to S3.

<?php

use \Aws\S3\S3Client;

/**
 * Implement hook_watchdog
 * @param array $log_entry
 */
function audit_watchdog(array $log_entry) {
    // Set the modules which needs to be logged to S3
    $modules = array(
        'module_1',
        'module_2',
        'module_3',
    );
    if (in_array($log_entry['type'], $modules)) {
        if(isset($log_entry) && !empty($log_entry)) {
            // Get the S3 config details
            $s3_config = variable_get("s3_config");
            $s3_bucket = $s3_config->s3_bucket;
            $s3_region = $s3_config->s3_region;
            $s3_key = $s3_config->s3_key;
            $s3_secret = $s3_config->s3_secret;
            try {
                if (!empty($s3_bucket) && !empty($s3_region) && !empty($s3_key) && !empty($s3_secret)) {
                    // Create AWS connection
                    $s3 = create_aws_connection($s3_region, $s3_key, $s3_secret);
                    if (!empty($s3) && is_object($s3) && $s3 != FALSE) {
                        if ($s3->doesBucketExist($s3_bucket)) {
                            $log_path = 'public://logs/to_aws';
                            // Create log directory
                            $dir_path = create_aws_log_directory($log_path);
                            // Create log file
                            $file_path = create_aws_log_file($log_entry, $dir_path);
                            // Get the name of log file
                            $keyname = get_keyname_for_log_file($log_entry['severity'], $file_path);
                            // Store the log file to S3
                            $s3->putObject([
                                'Bucket' => $s3_bucket,
                                'Key' => $keyname,
                                'Body' => '',
                                'SourceFile' => $file_path,
                            ]);
                            // Remove the directory & file created
                            if (is_dir($dir_path)) {
                                rmdir_recursive($dir_path);
                                rmdir_recursive('public://logs');
                            }
                        }
                    }
                }
            }
            catch (Exception $e) {
                // Exception is ignored so that watchdog does not break pages during the
                // installation process or is not able to create the watchdog table during
                // installation.
            }
        }
    }
}

function create_aws_connection($s3_region, $s3_key, $s3_secret) {
    $s3 = new S3Client([
        'version' => 'latest',
        'region'  => $s3_region,
        'credentials' => [
            'key'    => $s3_key,
            'secret' => $s3_secret,
        ]
    ]);
    $buckets = $s3->listBuckets()->get('Buckets');
    if (isset($buckets) && !empty($buckets)) {
        return $s3;
    }
    else {
        return FALSE;
    }
}

function create_aws_log_directory($log_path) {
    if (!is_dir($log_path)) {
        mkdir($log_path, 0777, true);
        chmod($log_path, 0777);
    }
    return $log_path;
}

function create_aws_log_file($log_entry, $dir_path) {
    $content = json_encode($log_entry);
    $log_file_name = $log_entry['type'] . '-' . date("Y-m-d-H-i-s") . '-' . preg_replace("/^.*\./i","", microtime(true)) . '.log';
    $file_path = $dir_path . '/' . $log_file_name;
    $log_file = fopen($file_path, "w");
    $write_log_file = fwrite($log_file, $content);
    $close_log_file = fclose($log_file);
    $chmod_log_file = chmod($file_path, 0777);
    return $file_path;
}

function get_keyname_for_log_file($severity, $file_path) {
    $watchdog_array = array(
        "0" => "WATCHDOG_ERROR",
        "1" => "WATCHDOG_INFO",
    );
    return 'drupal-logs/' . $watchdog_array[$severity] . '/' . basename($file_path);
}

function rmdir_recursive($dir) {
    foreach(scandir($dir) as $file) {
        if ('.' === $file || '..' === $file) continue;
        if (is_dir("$dir/$file")) rmdir_recursive("$dir/$file");
        else unlink("$dir/$file");
    }
    rmdir($dir);
}

Advantage of having Logs on S3

  • Reduce the number of DB log entries on Drupal database.
  • Completely Keep the Audit system outside Drupal, So Prod instance will play smooth.

Cheers :)

Jun 17 2019
Jun 17

Submitted by heykarthikwithu on Monday, 17 June 2019 - 14:18:28 IST

Run Simple test cases from terminal via Docker commands

from Drupal root, we could use the below command to run the test cases.

$ scripts/run-tests.sh --verbose --php /usr/local/bin/php Globe

In case, If we have a docker setup for our local envirnoment, we could use this below command to run the test cases.

$ docker exec -it drupal_phpfpm_1 /usr/local/bin/php scripts/run-tests.sh --verbose --php /usr/local/bin/php Custom

Where
drupal_phpfpm_1: Docker container name
/usr/local/bin/php: Path to the Php installation
Custom: Group name of the test cases

The same command could be used to run the test cases on you CI/CD envirnoment.

Jun 13 2019
Jun 13

To Perform an HTTP request in Drupal 7 we can use "drupal_http_request" function. This is a flexible and powerful HTTP client implementation. Correctly handles GET, POST, PUT or any other HTTP requests. Handles redirects.

Parameters

$url: A string containing a fully qualified URI.

array $options: (optional) An array that can have one or more of the following elements:

  • headers: An array containing request headers to send as name/value pairs.
  • method: A string containing the request method. Defaults to 'GET'.
  • data: An array or object containing the values for the request body or a string containing the request body, formatted as 'param=value&param=value&...'; to generate this, use http_build_query(). Defaults to NULL.
  • max_redirects: An integer representing how many times a redirect may be followed. Defaults to 3.
  • timeout: A float representing the maximum number of seconds the function call may take. The default is 30 seconds. If a timeout occurs, the error code is set to the HTTP_REQUEST_TIMEOUT constant.
  • context: A context resource created with stream_context_create().

Return value

object: An object that can have one or more of the following components:

  • request: A string containing the request body that was sent.
  • code: An integer containing the response status code, or the error code if an error occurred.
  • protocol: The response protocol (e.g. HTTP/1.1 or HTTP/1.0).
  • status_message: The status message from the response, if a response was received.
  • redirect_code: If redirected, an integer containing the initial response status code.
  • redirect_url: If redirected, a string containing the URL of the redirect target.
  • error: If an error occurred, the error message. Otherwise not set.
  • headers: An array containing the response headers as name/value pairs. HTTP header names are case-insensitive (RFC 2616, section 4.2), so for easy access the array keys are returned in lower case.
  • data: A string containing the response body that was received.

Examples

<?php

function create($data) {
    try {
        $response = drupal_http_request(FULLY_QUALIFIED_URL, [
            "headers" => [
                "Authorization" => "Basic " . authorization(),
                "Content-Type" => "application/json",
            ],
            "method" => "POST",
            "data" => json_encode(array(
                'id' => $data['id'],
                'values' => array(
                    'name' => $data['name'],
                    'email' => $data['email'],
                ),
            ))
        ]);
        if ($response->code == 201) {
            return json_decode($response->data);
        }
        else {
            watchdog('error', t($response->code . ' Error, while creating.'), (array) $response, WATCHDOG_ERROR);
            return NULL;
        }
    }
    catch (Exception $exception) {
        watchdog('exception', t('Exception - while creating.'), (array) $exception, WATCHDOG_ERROR);
    }
}

function get_all($filters) {
    try {
        $query = '';
        $build_query = http_build_query($filters);
        if(isset($build_query) && !empty($build_query)){
            $query = '?' . $build_query;
        }
        $response = drupal_http_request(FULLY_QUALIFIED_URL . $query, [
            "method" => "GET",
            "headers" => [
                "Authorization" => "Basic " . authorization(),
                "Content-Type" => "application/json",
            ],
        ]);
        if ($response->code == 200) {
            return json_decode($response->data);
        }
        else {
            watchdog('error', t($response->code . ' Error, while getting all.'), (array) $response, WATCHDOG_ERROR);
            return NULL;
        }
    }
    catch (Exception $exception) {
        watchdog('exception', t('Exception - while getting all.'), (array) $exception, WATCHDOG_ERROR);
    }
}

function get($id) {
    try {
        $response = drupal_http_request(FULLY_QUALIFIED_URL . '/' . $id, [
            "method" => "GET",
            "headers" => [
                "Authorization" => "Basic " . authorization(),
                "Content-Type" => "application/json",
            ],
        ]);
        if ($response->code == 200) {
            return json_decode($response->data);
        }
        else {
            watchdog('error', t($response->code . ' Error, while getting.'), (array) $response, WATCHDOG_ERROR);
            return NULL;
        }
    }
    catch (Exception $exception) {
        watchdog('exception', t('Exception - while getting.'), (array) $exception, WATCHDOG_ERROR);
    }
}

function update($id, $data) {
    try {
        $response = get($id);
        $result = $response->values;
        $response = drupal_http_request(FULLY_QUALIFIED_URL . '/' . $id, [
            "headers" => [
                "Authorization" => "Basic " . authorization(),
                "Content-Type" => "application/json",
            ],
            "method" => "PUT",
            "data" => json_encode(array(
                'values' => array(
                    'name' => isset($data['name']) ? $data['name'] : $result->name,
                    'email' => isset($data['email']) ? $data['email'] : $result->email,
                ),
            ))
        ]);
        if ($response->code == 200) {
            return json_decode($response->data);
        }
        else {
            watchdog('error', t($response->code . ' Error, while updating.'), (array) $response, WATCHDOG_ERROR);
            return NULL;
        }
    }
    catch (Exception $exception) {
        watchdog('exception', t('Exception - while updating.'), (array) $exception, WATCHDOG_ERROR);
    }
}

function delete($id) {
    try {
        $response = drupal_http_request(FULLY_QUALIFIED_URL . '/' . $id, [
            "method" => "DELETE",
            "headers" => [
                "Authorization" => "Basic " . authorization(),
                "Content-Type" => "application/json",
            ],
        ]);
        if ($response->code == 204) {
            return TRUE;
        }
        else {
            watchdog('error', t($response->code . ' Error, while deleting'), (array) $response, WATCHDOG_ERROR);
            return FALSE;
        }
    }
    catch (Exception $exception) {
        watchdog('exception', t('Exception - while deleting'), (array) $exception, WATCHDOG_ERROR);
    }
}

By using the above examples one can make the POST, GET, PUT & DELETE operations via drupal_http_request.

Cheers :)

Jun 11 2019
Jun 11

Advanced Encryption Standard, where we use “AES-256” to encrypt the data with Cipher. Encrypt & Decrypt approach taken is “Cipher Block Chaining” method “AES-256-CBC”.

AES Encrypt

  • We would have the “Secret” stored in a file which is other than the web root.
$key = hash('sha256', $secret, true);
  • Hash the “Secret” with sha256, this gives you the “Key” which will be used to openssl encrypt.
  • And Generate the pseudo random bytes as “IV”, so that it would be used during encryption and also be attached to the encrypted data.
$iv = openssl_random_pseudo_bytes(16);
  • Now encrypt the “String” with openssl encrypt by passing the “AES-256-CBC” method, “Key” and “IV”
$ciphertext = openssl_encrypt($plaintext, $method, $key, OPENSSL_RAW_DATA, $iv);
  • “openssl_encrypt” will Encrypt given data with given method and key, returns a raw or base64 encoded string.
  • “Hash” the returned “Cipher” text with sha256 hmac method
$hash = hash_hmac('sha256', $ciphertext, $key, true);
  • Now concatenate the “IV” & “Hash” & “Cipher” and store in the DB as the encrypted value.

AES Decrypt

  • Hash the “Secret” with sha256, this gives you the “Key” which will be used to openssl encrypt.
$key = hash('sha256', $password, true);
  • Explode the concatenated string to “IV” & “Hash” & “Cipher”
$iv = substr($ivHashCiphertext, 0, 16);

$hash = substr($ivHashCiphertext, 16, 32);

$ciphertext = substr($ivHashCiphertext, 48);
  • “openssl_decrypt” will take a raw or base64 encoded string and decrypts it using a given method and key.
  • Now decrypt the “Cipher” with “AES-256-CBC” method, “Key” and “IV”
openssl_decrypt($ciphertext, $method, $key, OPENSSL_RAW_DATA, $iv);
  • Return the decrypted “String”.it is ok, or do i need to change it to excel.

Cheers :)

Jun 27 2018
Jun 27

Attackers are exploiting Drupalgeddon 2 critical vulnerability in Drupal to compromise systems & secretly turn them into malicious cryptocurrency mining machines like cryptojacking malware, mine for Monero.

The only side effects a victim might notice is that their system is running slower or doing more work than usual.

Still most of the drupal sites those are not upgraded to with the patch are having the issue..

The worst case would be rebuilding your servers, Well you will notified by your hosting providers if you are on shared hosting and asked you to fix it because they have their AUP violations rules ;)

so, Adding the security patch and cleaning up system would be task if at all you don't choose to rebuild servers..
 

Here we go, with understanding and cleaning

Remote Code Execution - SA-CORE-2018-004
Fix for this remote code execution vulnerability was released in Drupal - 7.39/8.5.4

Check and keep the backup of the drupal site, obviously hosting provider and we have a backup for atleast a month or 3 months.
Replicate the site on different server with backup and keep it aside..

In parallel to above step, Get one of the best anti-malware tools and perform scan on server, specifically for remote code execution like BitDefender. Else if you have any penetration tools could be used for scanning.

Upgrade the drupal to the latest version Drupal - 7.39/8.5.4..!!

Cleanup Decision would be made based on the result of the scan..?
Ideally if you see, less amount of vulnerable files the delete those..
Particularly should be checked for php5 files, any crons included on crontabs or any perl scripts running automatically such things should be stopped..

Find out any outgoing request going from the server, if at all any suspicious url / activity is seen kill those, if they are initiated again, find for the ones which are initiating these tasks and kill those..

That's it..
If you are not seeing any activity, site is safe.. Get the penetration tests in a scheduled manner, so that if any other comes that could be captured and easy to fix it..
Bad case here would be, if you are still seeing outgoing activity from your server.. then rebuilding the servers is the option.

Cheers :)

Original Post - https://karthikkumardk.blogspot.com/2018/06/sites-still-vulnerable-to-drupalgeddon-2.html

Feb 01 2018
Feb 01

Website security is generally most complicated and expensive task for every Linux admin. Let’s Encrypt is a free, automated, and open certificate authority that provides free X.509 certificates for Transport Layer Security encryption via an automated process. It's very complex process to install and add SSL certificate to a web server. Let's make it easier with the help of Let’s Encrypt. One can easily encrypt data of your website free of charge using Let’s Encrypt.

If your Site is running on Apache, run this below one to enable ssl..

sudo a2enmode ssl
sudo a2ensite default-ssl

Next restart the apache webserver

sudo systemctl restart apache2

If you hit your domain, you will see 

Your Connection is not Secured

Download and Install Let’s Encrypt

sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencrypt

Next generate the Certificate

cd /opt/letsencrypt
sudo ./letsencrypt-auto --apache -d kkk.com

During installation you will need to specify your E-mail address and also agree to the terms of service.

Once completed, One can see list all of certificate files at /etc/letsencrypt/live directory..

And you can access https://kkk.com

You can also verify the status of your SSL certificate by visiting the URL https://www.ssllabs.com/ssltest/analyze.html?d=yourdomain.com&latest

How to Renew Lets Encrypt Certificates ??

By default, SSL certificates issued by Let’s Encrypt are valid for 90 days. So it is recommended to renew the certificate before the expiration date.

You can renew the SSL certificates manually

cd /opt/letsencrypt
sudo ./letsencrypt-auto certonly --renew-by-default -d kkk.com

to Automate this process, lets have the Cron job for this to do..

sudo nano /etc/crontab

 @monthly root /opt/letsencrypt/letsencrypt-auto certonly --renew-by-default -d kkk.com

Save this file and Every month, this cron job would run..

Upgrade Let's Encrypt

cd /opt/letsencrypt

Pull the latest changes from the git repository..

Cheers :)

Jan 18 2018
Jan 18

Encrpt and Decrypt text in the URL's

In general, while Anonymous user's are given access to make some DB operations via UI, then important thing to make sure is its not hackable..  

For this to make sure, minimum thing to do is encrypt the piece of text for the end user and decrypt back piece of text while doing the backend operation..

This can be done as seen below

Rendered URL, where node id is encrypted

<a href="http://dev-karthikkumardk.pantheonsite.io/abt/cancel/'. fmg_encrypt($entity->nid) .'">here</a>

Encrypt function

function fmg_encrypt($str) {
  $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
  $iv = openssl_random_pseudo_bytes($ivlen);
  $key = "fmg_sec";
  $ciphertext_raw = openssl_encrypt($str, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
  $hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
  $ciphertext = base64_encode( $iv.$hmac.$ciphertext_raw);
  return base64_encode($ciphertext);
}

Decrypt function

function fmg_decrypt($str) {
  $tmp = base64_decode($str);
  $c = base64_decode($tmp);
  $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
  $iv = substr($c, 0, $ivlen);
  $hmac = substr($c, $ivlen, $sha2len=32);
  $ciphertext_raw = substr($c, $ivlen+$sha2len);
  $key = "fmg_sec";
  $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
  $calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true);
  if (hash_equals($hmac, $calcmac))//PHP 5.6+ timing attack safe comparison
  {
    return $original_plaintext."\n";
  }
}

Decrypt back the node id back

$node = node_load(trim(fmg_decrypt($str)));

Cheers :)

Oct 23 2017
Oct 23

Submitted by heykarthikwithu on Monday, 23 October 2017 - 11:32:54 IST

Get the Module/Theme via require..

$ composer require drupal/imagefield_slideshow

Using version ^1.5 for drupal/imagefield_slideshow
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Installing heykarthikwithu/cycle (1.1): Downloading (100%)         
> Drupal\Core\Composer\Composer::vendorTestCodeCleanup
  - Installing drupal/imagefield_slideshow (1.5.0): Downloading (100%)         
> Drupal\Core\Composer\Composer::vendorTestCodeCleanup
Writing lock file
Generating autoload files
> Drupal\Core\Composer\Composer::preAutoloadDump
> Drupal\Core\Composer\Composer::ensureHtaccess

And Interesting "drupal-init".. cheers :)

Composer Drupal 8

Composer Drupal 7

Sep 03 2017
Sep 03

Aegir with Docker would be one of the brilliant option for Better Drupal Development and Faster Deployments.

Docker, which solves the overhead of virtualization layer. And Aegir, which gives the best possible approach for Drupal Multisite hosting.

Here you go???

Better Task Queue..! This process is usually handled by "Supervisor"
The “task queue runner” is just a continuous process that aegir must always have running, so that it can respond to actions on the front-end in a reasonable amount of time.

Upon Docker Container's run, if we have "drush @hostmaster hosting-queued" it keeps queued items running.

Starting OR Re-starting Nginx/Apache would be handled by Aegir's "Verify" task.

This Could be one of the Future Feature of Aegir.. Since, In case of Process Failures.. Docker containers can be back up-running in seconds.

Faster and Easier Local Development could be made, once the images are downloaded.. Having Development, Preview and Production folders which could individually read each Dockerfiles, this would be next-gen local Drupal development tool..

Have Behat OR Codeception tests to make sure everything is moved between Platforms is tested well..

Travis could be better integration to have the CI in place, with this setup..

In near future, I would get this setup in place.. Stay tuned for more posts on Aegir and Docker..

Aug 06 2017
Aug 06

Submitted by heykarthikwithu on Sunday, 06 August 2017 - 22:09:58 IST

Some Best Practices in Drupal 7's Optimization in Performance can be achieved..

Hot Content on Site

13 Jun 2019 - 16:58

Milton Thermosteel Duo DLX-1800 Stainless Steel Water Bottle, 1.8 litres, Steel

13 Jun 2019 - 15:03

Leaf Bass Wireless Headphones with Mic and 10 Hour Battery Life

13 Jun 2019 - 10:32

Perform HTTP request in Drupal 7

12 Jun 2019 - 08:01

R for Rabbit Lollipop Lite The Colourful Baby Stroller and Pram (Rainbow)

11 Jun 2019 - 16:30

AES Encrypt & Decrypt

5 Jun 2019 - 09:50

Malhotra Plastic Plastic Stack-A-Pot Hanging Set (Terracotta, 5-Pieces)

Pagination

Jul 31 2017
Jul 31

Submitted by heykarthikwithu on Monday, 31 July 2017 - 08:37:46 IST

With Some Best Practices with Drupal 8's Configuration Management will help you to achieve packaging reusable functionality.

Hot Content on Site

13 Jun 2019 - 16:58

Milton Thermosteel Duo DLX-1800 Stainless Steel Water Bottle, 1.8 litres, Steel

13 Jun 2019 - 15:03

Leaf Bass Wireless Headphones with Mic and 10 Hour Battery Life

13 Jun 2019 - 10:32

Perform HTTP request in Drupal 7

12 Jun 2019 - 08:01

R for Rabbit Lollipop Lite The Colourful Baby Stroller and Pram (Rainbow)

11 Jun 2019 - 16:30

AES Encrypt & Decrypt

5 Jun 2019 - 09:50

Malhotra Plastic Plastic Stack-A-Pot Hanging Set (Terracotta, 5-Pieces)

Pagination

Jul 06 2017
Jul 06

Submitted by heykarthikwithu on Thursday, 06 July 2017 - 14:06:12 IST

How to setup Multiple Drush's in your machine, to manage the drupal 6, drupal 7 and drupal 8 sites..

Hot Content on Site

13 Jun 2019 - 16:58

Milton Thermosteel Duo DLX-1800 Stainless Steel Water Bottle, 1.8 litres, Steel

13 Jun 2019 - 15:03

Leaf Bass Wireless Headphones with Mic and 10 Hour Battery Life

13 Jun 2019 - 10:32

Perform HTTP request in Drupal 7

12 Jun 2019 - 08:01

R for Rabbit Lollipop Lite The Colourful Baby Stroller and Pram (Rainbow)

11 Jun 2019 - 16:30

AES Encrypt & Decrypt

5 Jun 2019 - 09:50

Malhotra Plastic Plastic Stack-A-Pot Hanging Set (Terracotta, 5-Pieces)

Pagination

Jun 28 2017
Jun 28

Submitted by heykarthikwithu on Wednesday, 28 June 2017 - 12:05:12 IST

The Drupal CLI. A tool to generate boilerplate code, interact with and debug Drupal.

Hot Content on Site

27 Jun 2018 - 12:55

Sites Still Vulnerable to Drupalgeddon 2

1 Feb 2018 - 12:07

Secure Website running on Apache with Let's Encrypt on Linux

18 Jan 2018 - 18:19

Encrpt and Decrypt text in the URL's

23 Oct 2017 - 14:18

Installing & Setting up the Symfony Framework

23 Oct 2017 - 11:32

Composer in Drupal 8 - Manage dependencies

3 Sep 2017 - 17:00

Aegir on Docker - Develop, Test, With Easier Deployment.

Pagination

Jun 26 2017
Jun 26

Submitted by heykarthikwithu on Monday, 26 June 2017 - 12:52:01 IST

Hot Content on Site

27 Jun 2018 - 12:55

Sites Still Vulnerable to Drupalgeddon 2

1 Feb 2018 - 12:07

Secure Website running on Apache with Let's Encrypt on Linux

18 Jan 2018 - 18:19

Encrpt and Decrypt text in the URL's

23 Oct 2017 - 14:18

Installing & Setting up the Symfony Framework

23 Oct 2017 - 11:32

Composer in Drupal 8 - Manage dependencies

3 Sep 2017 - 17:00

Aegir on Docker - Develop, Test, With Easier Deployment.

Pagination

Jun 15 2017
Jun 15
Drupal - simplytest.me, Evaluate Drupal Projects Online

How to use simplytest.me, to evaluate drupal projects online?

heykarthikwithu Thursday, 15 June 2017 - 08:50:40 IST
Jun 05 2017
Jun 05
Home

Drupal 7 - Apache Solr Search, How to setup and how to index?

Submitted by heykarthikwithu on Monday, 05 June 2017 - 13:25:09 IST

1. Install Solr on the machine.
2. Setup the Core.
3. Install and Configure the Apache Solr Search module.
4. Search Indexing.

These things are briefed in the video with screenshots..

May 30 2017
May 30
Home

Drupal 8 - Form API, options we have in #states ?

Submitted by heykarthikwithu on Tuesday, 30 May 2017 - 18:46:19 IST

Drupal 8, Form API #states allow us to create form elements that change state (show, hide, enable, disable, etc.) depending on certain conditions..

Its one of the power full feature, Like for simple form interactions its providing a consistent JS code.

Here's a small video, brief about the usage..

May 27 2017
May 27
Home

Drupal 8 - Simple Redirect Module, Redirect from one url to another url.

Submitted by heykarthikwithu on Saturday, 27 May 2017 - 15:40:09 IST

This is a light weight Module provide user to have redirects in website.

Simple Redirect Module - 8.x-1.x module was providing redirect upon Registration and Login. In 8.x-3.x its different for all the url's in the site we can have redirects.

CONFIGURATION

8.x-3.x
In the 3.x version, user is allowed to configure his own redirects via entity config.
After enabling module, visit, /admin/config/simple_redirect url, here one can add their own redirects.

Note : 1.x version is completely different from 3.x version, One who is updating to 3.x version should uninstall, remove 1.x module and download, install the 3.x module

Similar modules, with more features.
Redirect - https://www.drupal.org/project/redirect

May 12 2017
May 12
Why DevOps is important? How this can be done in Drupal?

This video will give you a brief idea about the 2 questions..!

heykarthikwithu Friday, 12 May 2017 - 12:31:22 IST
Apr 06 2017
Apr 06

Submitted by heykarthikwithu on Thursday, 06 April 2017 - 13:00:00 - IST, Asia/Kolkata

The Imagefield Slideshow makes it easy to create a slideshow from just an image field.

Imagefield Slideshow module will provide a field formatter for image fields, so that if multiple images are uploaded to that particular image field and this formatter helps you to render those images as a slideshow.

For more details check out the Imagefield Slideshow project page.

Getting Started

Lets install the latest version 8.x-1.5 of the module.

  1. Initially download the module to the modules directory via drush / drupal console / manually.
  2. Then do a composer update from the module folder.
    $composer update
    which will get the cycle library to imagefield slideshow modules vendor directory.
  3. Enable the Imagefield Slideshow module.
  4. You should now see a new field formatter Imagefield Slideshow for image fields, Ex: under Manage display section of content types

Configuration

Visit any image fields display settings, you will be able to find the Imagefield Slideshow formatter, select this one.
Ex: admin/structure/types/manage/article/display
And you can also see image styles which are mentioned in Available options.

Available options

  • Image style
  • Link
  • Transition effect
  • Transition speed
  • Prev/Next controls

Integration

This module works well with..
Colorbox Module.
Field Collection Module.
And Core modules, where fields are used, like Views.

Similar module in Drupal 7

Field Slideshow - https://www.drupal.org/project/field_slideshow

Thank you :)

Mar 26 2017
Mar 26

Submitted by heykarthikwithu on Sunday, 26 March 2017 - 14:53:41 - IST, Asia/Kolkata

Getting Codeception into Drupal, will have added support for Test Driven Development.. Specifically in having the Acceptance Tests in the project.. Since Test Driven Development would be one the most integral part of the project.. And also internal team and vendor team would be having more confidence in the version releases of their project.. one can prefer TDD.

Test driven development is an evolutionary approach to development which combines test-first development where you write a test before you write just enough production code to fulfill that test and refactoring.

  • For the entire lifespan of your project, you have tests for the features you build.
  • Speeds up development
  • Ensures you write good quality code/build good quality features

So, here we get Codeception for having our TDD approach.

What is CODECEPTION?

  1. Powered by PHPUnit
  2. VERY easy to extend
  3. Run any type of test you may want to
     - Acceptance
     - Functional
     - Unit
  4. Build your own suite with a combination of provided modules (CLI suite for custom Drush commands)
  5. Run all your different test types from one source

Installation

In composer.json

"require": {
    "codeception/codeception": "2.2"
},

Or

composer require codeception/codeception --dev

Setup

$ php vendor/bin/codecept bootstrap

How to Run it

php vendor/bin/codecept run

Its well documented, in the Codeception docs, like how to generate the test cases, extend and run those..

And I have a Demo piece of code in the Git which helps to setup very easily..

Thank you :)

Mar 22 2017
Mar 22
Setup the Drupal 8 site in the Pantheon instance

This video will show you, like how to setup Drupal 8 site in the Pantheon server..!

heykarthikwithu Wednesday, 22 March 2017 - 15:30:22 - IST, Asia/Kolkata
Mar 16 2017
Mar 16

Submitted by heykarthikwithu on Thursday, 16 March 2017 - 08:02:50 - IST, Asia/Kolkata

Simple Redirect Module provide us simple redirection feature upon Registration and Login.

INSTALLATION

  • Install as you would normally install a contributed Drupal module.
    See: here for further information.

CONFIGURATION

  • Visit admin/config/simple-redirect settings page, and provide the url to redirect upon registration and login.

HOW IT WORKS

The redirect in 8.x-1.0 is happening by get the valid url via path validator and redirecting the response as shown below.

$url = \Drupal::pathValidator()->getUrlIfValid($toUrl);
$url->setAbsolute();
$redirect = $url->toString();
(new RedirectResponse($redirect))->send();

Thank you :)

Mar 14 2017
Mar 14

How to Create a Twitter Share block programmatically in Drupal 8. Which includes few minor stuff like

  1. Accessing the Current Node data in Block.
  2. How do we create the link programmatically.
  3. Disable cache for particular block..
     
  public function build() {
    $node = \Drupal::request()->attributes->get('node');
    $options = array(
      'query' => array(
        'text' => t($node->getTitle()),
        'hashtags' => t('drupal'),
        'via' => t('heykarthikwithu'),
      ),
      'attributes' => array(
        'target' => '_blank',
        'class' => 'twitter-share'
      ),
    );
    $url = Url::fromUri('https://twitter.com/share', $options);
    $link = Link::fromTextAndUrl('Share it on Twitter..?', $url);
    $build['#markup'] = $link->toString();
    $build['#cache']['max-age'] = 0;
    return $build;
  }

Well this was the piece of code which is written in this site to share content in Twitter..

1. Accessing the Current Node data in Block

$node = \Drupal::request()->attributes->get('node');

2. To Create the link programmatically..

    $options = array(
      'query' => array(
        'text' => t($node->getTitle()),
        'hashtags' => t('drupal'),
        'via' => t('heykarthikwithu'),
      ),
      'attributes' => array(
        'target' => '_blank',
        'class' => 'twitter-share'
      ),
    );
    $url = Url::fromUri('https://twitter.com/share', $options);
    $link = Link::fromTextAndUrl('Share it on Twitter..?', $url);
    $build['#markup'] = $link->toString();

3. To disable cache for particular block..

$build['#cache']['max-age'] = 0;

Thank you :)
 

Feb 14 2017
Feb 14

Less Critical - Cross Site Scripting (XSS)

1. Use strip_tags

- <img src="http://dev-karthikkumardk.pantheonsite.io/Security-Checklist-for-Drupal/... echo $_GET['path']; ?>/doc/images/qb_search_settings.png" width="800" />
+ <img src="http://dev-karthikkumardk.pantheonsite.io/Security-Checklist-for-Drupal/... echo strip_tags($_GET['path']); ?>/doc/images/qb_search_settings.png" width="800" />

2. Use check_markup

- $form[$filter_id]['#bef_term_descriptions'][$tid] = $term->description;
+ $form[$filter_id]['#bef_term_descriptions'][$tid] = check_markup($term->description, $term->format, '', TRUE);

Moderately Critical - Access Bypass

1. Menu to be cached per role http://cgit.drupalcode.org/wetkit_omega/commit/?id=ce4b66dd751b5279dc37…

'expire' => CACHE_TEMPORARY,
- 'granularity' => DRUPAL_CACHE_PER_PAGE, // unset this to cache globally
+ 'granularity' => DRUPAL_CACHE_PER_ROLE, // unset this to cache globally
);

Moderately Critical - Multiple vulnerabilities

1.  Use filter_xss

$data = $node_wrapper->{$field}->value();
+ $clean_name = filter_xss($data->name);
- $render = l($data->name, 'node/' . $todo_list_nid,
+ $render = l($clean_name, 'node/' . $todo_list_nid,

Sep 27 2015
Sep 27

This article help you to create the way to implement the autotagging of the taxonomy terms based on the other field of the node page.

This can be implemented by using the hook_node_presave().

In our case lets consider the field_tags is the taxonomy field, and we are autotagging based on the content present in title and body fields.

All these actions are implemented inside the hook_node_presave().
 

1. First thing is getting the list of terms of the field_tags vocabulary, this is done in the below code.

$field = field_info_field('field_tags');
// read the field information.
$voc_name = $field["settings"]["allowed_values"][0]["vocabulary"];
// get the vocabulary name which is been configured for the tag field.
$voc = taxonomy_vocabulary_machine_name_load($voc_name);
// load the vocabulary object.
$terms = taxonomy_term_load_multiple(array(), array('vid' => $voc->vid));
// get all the terms in the vocabulary.
$termnames = array();
foreach($terms as $termskey => $termsvalue) {
    $termnames[$termskey] = $termsvalue->name;
}

// iterating the terms objects and getting out the terms names out of it.

2. So now we have the $termnames which needs to be cross checked with the content in the title and body fields, this is done in the below code.

// read the node title and body and stored in the $content.
$content = $node->title;
$content .= $node->body['und'][0]['value'];
// Iterate all the terms and compare with the content words, if matched then store them in seperate array.
$node_tids = array();
foreach($termnames as $termname) {
    if (strpos($content, $termname) !== false) {
        $term = taxonomy_get_term_by_name($termname);
        foreach($term as $termkey => $termvalue) {
            $node_tids[] = (array) $termvalue;
        }
    }
}

3. After this, we will have the term ids $node_tids which needs to be saved as autagged terms, this is just assinging to node object $node.

$node->field_tags["und"] = $node_tids;

Note: In case of exisisting node in be updated, we should take care of the existing terms which are saved in the node, to do this we need to add some code which does it.

$node_tids_all = array();
// check if any existing terms are their in the field_tags
if(!empty($node->field_tags)) {
       // in case not empty, merge the terms with the existing terms.
    $node_tids_all = array_merge_recursive($node->field_tags["und"], $node_tids);
}

// In case any duplicates exist, get out the unique ones.
$node_tids_all = array_map("unserialize", array_unique(array_map("serialize", $node_tids_all)));
// then assign the selected terms to the node object.
$node->field_tags["und"] = $node_tids_all;

So, thats it, return the $node object at the end of the hook_node_presave(). this autotags the term field with title and body field.

Thank you :)

Sep 27 2015
Sep 27

This article is an example of how to add a field formatter to the field, this is been achieved through the field formatter hooks.

Field formatters are used to render fields in node views. Drupal provides default formatters.
To customize the output of a field and have it apply it to multiple fields of the same type, a custom formatter needs to be created.

To start look at the default formatters available for the link field in a Content Type. In Drupal 7 the available formatters for a field are found by going to Structure > Content types > The content type > Manage display. and you can see here list field formatters for each field.

To create a custom field field formatter.
1. Defining a Field Formatter.
2. Themeing the Field Formatter.

1. Defining a Field Formatter

To define a formatter in Drupal 7, two hooks need to be called: hook_field_formatter_info() and hook_field_formatter_view().

<?php
/**
* Implements hook_field_formatter_info().
*/

function mymodule_field_formatter_info() {
  $info = array(
    'website' => array(
      'label' => t('My module url.'),
      'field types' => array('link_field'),
      'description' => t('A customized link for My module only.'),
    ),
  );
  return $info;
}

?>

The field types represents the field type, currently this is a link field.

<?php
/**
* Implements hook_field_formatter_view().
*/
function mymodule_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  switch ($display['type']) {
    case 'website':
      foreach ($items as $delta => $item) {
        $element[$delta] = array(
          '#theme' => 'mymodule_field_formatter',
          '#title' => $entity->field_website['und'][0]['title'],
          '#url' => $entity->field_website['und'][0]['url'],
        );
     }
      break;
  }
  return $element;
}
?>

 

The #title and #url are the values which would be accessable for the template file.
And #theme value mymodule_field_formatter would be the theme variable which would be themed in hook_theme.
 

2. Themeing the Field Formatter

To theme the formatter, the hook_theme() needs to be implemented. This is where the template file is called.

<?php
/**
* Implements hook_theme().
*/
function mymodule_theme() {
  return array(
    'mymodule_field_formatter' => array(
      'template' => 'mymodule_field_formatter',
      'variables' => array(
        'title' => NULL,
        'url' => NULL,
      ),
    ),
  );
}
?>

The mymodule_field_formatter is the name of the template, which needs to be implemented, so this file name would be like mymodule_field_formatter.tpl.php
this template file would contain the following code.

<a href="http://dev-karthikkumardk.pantheonsite.io/Custom-field-formatter-in-Drupal7/<?php print $url; ?>"><?php print $title; ?></a>
<div class="website-title"><?php print $url; ?></div>

Thats it, the new field formatter "My module url." would be created in the link field formatters list, which can be used.
This field formatter can also be used in the views.
And another hook, hook_field_formatter_prepare_view which can be used to alter the rendering of the field.

Thank You..!

Sep 26 2015
Sep 26
Start Migrating Drupal 6 to Drupal 7 - Migrate Module

To develop custom migration processes based on the Migrate framework, you will need to create your own Migration classes in a custom module. and these will help you out in migrating D6 content to D7.

heykarthikwithu Sat, 09/26/2015 - 20:23
Sep 18 2015
Sep 18

The Drupal 7 Hook Concept

Drupal’s hook system allows modules to interact with and alter data of other modules (even Drupal core).
To use a hook system you should create it (and call the implementations (invoking)) and implement it.

By reading this page you will have a solid understanding of hook concept and will see a few basic examples.
 

Creating a Drupal 7 hook (and calling their implementations)

Creating a hook and calling their implementations can be done by using one of the following functions:
1. drupal_alter()
2. module_invoke_all()
3, module_invoke()

Aug 26 2015
Aug 26

Debugging the code is one of the important process for a developer,
So now this article will help you to configure the Phpstorm for debugging the Drupal 7 application with the help of xDebug.

The configuration made in this article refers specifically to the Ubuntu machine, which has Apache2 webserver running and xDebug installed.

Initally open terminal, and check the php version

$ php -v

you will get the following output

PHP 5.6.12-1+deb.sury.org~trusty+1 (cli)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies
    with Xdebug v2.3.2, Copyright (c) 2002-2015, by Derick Rethans

In my case, since xdebug is already installed, it showing xdebug else you should install the xdebug., follow below command to install xdebug.

$ pecl install xdebug

Next find the path of the file where xdebug.so is located, you can find by this command $ locate xdebug.so

Next, you got to the php.ini file, in my case its located in /etc/php5/apache2/php.ini Or to find where its is located you can find by this command $ locate php.ini

Next, you need to add below lines to the php.ini file

zend_extension="/usr/lib/php5/20131226/xdebug.so"
xdebug.remote_port="9001"
xdebug.remote_enable="1"
xdebug.idekey="PHPSTORM"

Next, Open PhpStorm -> File -> Default Settings -> In the search box search with ‘debug’, Change ‘Debug port’ to 9001, apply and ok.

Again Open File -> Default Settings -> Search for ‘IDE Key’, Set IDE key as ‘PHPSTORM’, Apply & OK

Next, Goto you browser, install an Xdebug helper extension.

Once you have enabled extension then you need to add Debugger bookmarklets for chrome. Go to https://www.jetbrains.com/phpstorm/marklets/ page & Generate XDebugger bookmarks.

Note : IDE key should be PHPSTORM, as we set in PhpStorm settings.

Now Drag & drop - Start debugger & Stop debugger to your browsers bookmarks Bar.

Now it’s time to debug our drupal 7 site with phpstorm & your browser.

Open PhpStorm with drupal 7 project & click ‘Start listen for PHP Debug connections’ (These option are at Top Right corner of your phpstorm)

Now open your browser & click on ‘Start debugger’ in the bookmark toolbar.

Again, Goto phpstorm. Now add breakpoint in index.php file.

Next, Again visit your browser and load any page (localhost/drupal7). For the first time phpstorm you will ask be asked for confirmation dialogue box to accept connection from browser. Once you accept it, you will be automatically  taken to you phpstorm's breakpoint.

In this way you can put multiple breakpoints and debug the code.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web