php Archives - Justin Silver https://www.justinsilver.com/tag/php/ Technology, Travel, and Pictures Mon, 02 Dec 2019 23:44:39 +0000 en-US hourly 1 https://wordpress.org/?v=6.0.1 https://www.justinsilver.com/wp-content/uploads/2013/06/cropped-apple-touch-icon-160x160.png php Archives - Justin Silver https://www.justinsilver.com/tag/php/ 32 32 Using APK for Alpine Linux with Docker https://www.justinsilver.com/technology/linux/using-apk-for-alpine-linux-with-docker/?utm_source=rss&utm_medium=rss&utm_campaign=using-apk-for-alpine-linux-with-docker https://www.justinsilver.com/technology/linux/using-apk-for-alpine-linux-with-docker/#respond Mon, 02 Dec 2019 23:41:36 +0000 https://www.justinsilver.com/?p=4902 Some quick tips on how to use apk for Alpine Linux in a Docker environment. Some common use cases might be to install command line tools you will use in scripts, or to compile...

The post Using APK for Alpine Linux with Docker appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

Some quick tips on how to use apk for Alpine Linux in a Docker environment. Some common use cases might be to install command line tools you will use in scripts, or to compile a PHP extension. In the former you will often be able to access a binary, and not need to worry about polluting much of your Docker layer with extra files. When you need to compile something however – like a PHP extension – you may need several build tools as well as libraries that you don’t need to keep around after you compile the module.

This first example is common for installing command line tools:

RUN apk add --no-cache --update \
  bash curl findutils sed sudo

The next example shows how to compile PHP modules and remove their dependencies after compilation.

RUN set -xe; \
    apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
      # build tools
      autoconf g++ gcc make \
      # lib tools
      bzip2-dev freetype-dev gettext-dev icu-dev imagemagick-dev libintl libjpeg-turbo-dev \
      #  libmcrypt-dev 
      libpng-dev libxslt-dev libzip-dev \
      ; \
    docker-php-ext-configure \
      gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/ \
      ; \
    docker-php-ext-install -j$(nproc) \
      bcmath bz2 calendar exif gettext gd intl mysqli opcache pcntl pdo_mysql soap xsl zip \
      ; \
    pecl channel-update pecl.php.net && \
    pecl install -o -f \
      redis \
      ; \
    docker-php-ext-enable \
      redis \
      ; \
    runDeps="$( \
      scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \
        | tr ',' '\n' \
        | sort -u \
        | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \
    )"; \
      apk add --virtual .phpexts-rundeps $runDeps; \
      apk del .build-deps

The post Using APK for Alpine Linux with Docker appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/linux/using-apk-for-alpine-linux-with-docker/feed/ 0
Install PHP 7.0 (phpng) on CentOS & RedHat https://www.justinsilver.com/technology/install-php-7-0-phpng-on-centos-redhat/?utm_source=rss&utm_medium=rss&utm_campaign=install-php-7-0-phpng-on-centos-redhat https://www.justinsilver.com/technology/install-php-7-0-phpng-on-centos-redhat/#respond Tue, 04 Aug 2015 23:41:29 +0000 http://justinsilver.com/?p=3890 This guide will show how to install PHP 7.0 on RedHat and CentOS Linux. This version of PHP is also known as PHPNG to indicate it is the “next generation” of PHP. Many fundamental improvements...

The post Install PHP 7.0 (phpng) on CentOS & RedHat appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

This guide will show how to install PHP 7.0 on RedHat and CentOS Linux. This version of PHP is also known as PHPNG to indicate it is the “next generation” of PHP. Many fundamental improvements have been made – for example WordPress sites should see a 100% performance increase switching from PHP 5.6 to PHP 7.0.

Install Dependencies via Yum

Use yum to install the dependencies we’ll need using the following command.

yum install -y \
    autoconf \
    bison \
    curl-devel \
    gcc \
    git \
    freetype\
    freetype-devel \
    libpng\
    libpng-devel \
    libxml2\
    libxml2-devel \
    libXpm\
    libXpm-devel \
    libmcrypt \
    libmcrypt-devel \
    mysql \
    mysql-devel \
    openssl \
    openssl-devel \
    recode \
    recode-devel

Running a newer version of RedHat/CentOS?

If you are running a recent version of your operating system, you can use yum to install bison. Note that it needs to be at least version 2.7 to compile PHPNG. As of the writing the latest for CentOS 5 on a yum repository is version 2.3, so you will need to install from source (below).

Install Bison 2.7 From Source

curl -O http://ftp.gnu.org/gnu/bison/bison-2.7.1.tar.gz
tar -xvf bison-2.7.1.tar.gz
cd bison-2.7.1
./configure
make && make install

Build PHPNG From Source

Now we need to clone the PHP-7.0.0 branch of the PHP source and compile it using the built in scripts.

git clone -b PHP-7.0.0 https://github.com/php/php-src.git
cd php-src
./buildconf --force
./configure \
    --prefix=/usr/local/opt/phpng \
    --with-config-file-path=/usr/local/etc/phpng \
    --enable-bcmath \
    --enable-calendar \
    --enable-exif \
    --enable-ftp \
    --enable-gd-native-ttf \
    --enable-gd-jis-conv \
    --enable-mbstring \
    --enable-sysvmsg \
    --enable-sysvsem \
    --enable-sysvshm \
    --enable-pcntl \
    --enable-wddx \
    --enable-zip \
    --with-bz2=/usr \
    --with-curl=/usr/lib64 \
    --with-freetype-dir=/usr \
    --with-gd \
    --with-gettext=/usr \
    --with-iconv \
    --with-jpeg-dir=/usr \
    --with-mcrypt \
    --with-mysql=/usr \
    --with-mysqli=/usr/bin/mysql_config \
    --with-openssl \
    --with-pdo-mysql=/usr \
    --with-png-dir=/usr \
    --with-recode=/usr \
    --with-t1lib=/usr \
    --with-xpm-dir=/usr \
    --with-zlib-dir=/usr \
    --with-zlib=/usr
make -j`grep -c ^processor /proc/cpuinfo` && make install

Use PHPNG

By default OS X will use the PHP binary located at /usr/bin/php, which as of this writing is PHP 5.5. To have PHPNG take precedence, will need to symlink to the /usr/local/bin directory. Run php -v to make sure you have the correct version, and if it’s not what you expected try which php to see the location that is being selected based on your $PATH.

ln -s /usr/local/opt/phpng/bin/php /usr/local/bin
php -v

PHP 7.0.0beta2 (cli) (built: Aug  3 2015 13:22:21) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies

The post Install PHP 7.0 (phpng) on CentOS & RedHat appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/install-php-7-0-phpng-on-centos-redhat/feed/ 0
Install PHP 7.0 (phpng) on Mac OS X https://www.justinsilver.com/technology/install-php-7-0-phpng-on-mac-os-x/?utm_source=rss&utm_medium=rss&utm_campaign=install-php-7-0-phpng-on-mac-os-x https://www.justinsilver.com/technology/install-php-7-0-phpng-on-mac-os-x/#comments Mon, 03 Aug 2015 20:50:58 +0000 http://justinsilver.com/?p=3880 This guide will show how to install PHP 7.0 on on Mac OS X. This version of PHP is also known as PHPNG to indicate it is the “next generation” of PHP. Many fundamental...

The post Install PHP 7.0 (phpng) on Mac OS X appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

This guide will show how to install PHP 7.0 on on Mac OS X. This version of PHP is also known as PHPNG to indicate it is the “next generation” of PHP. Many fundamental improvements have been made – for example WordPress sites should see a 100% performance increase switching from PHP 5.6 to PHP 7.0.

Install Brew

To start you will need to install Brew so that we can use it to install additional dependencies. Open Terminal and at the prompt enter the following.

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Install Dependencies

Once Brew is installed, install the dependencies we’ll need using the following command. Make sure you have tapped homebrew/versions to access all dependencies (it won’t hurt to run it again if you’ve think you’ve tapped it, but aren’t sure).

brew tap homebrew/versions
brew install \
    autoconf \
    automake \
    bison27 \
    freetype \
    gd \
    gettext \
    git \
    mariadb \
    mcrypt \
    t1lib \
    zlib

Build PHPNG From Source

Now we need to clone the PHP-7.0.0 branch of the PHP source and compile it using the built in scripts.

git clone -b PHP-7.0.0 https://github.com/php/php-src.git
cd php-src
./buildconf --force
env YACC=`brew --prefix bison27`/bin/bison ./configure \
    --prefix="/usr/local/opt/phpng" \
    --with-config-file-path="/usr/local/etc/phpng" \
    --enable-bcmath \
    --enable-calendar \
    --enable-exif \
    --enable-ftp \
    --enable-gd-native-ttf \
    --enable-gd-jis-conv \
    --enable-mbstring \
    --enable-pcntl \
    --enable-sysvmsg \
    --enable-sysvsem \
    --enable-sysvshm \
    --enable-wddx \
    --enable-zip \
    --with-bz2 \
    --with-curl \
    --with-iconv \
    --with-freetype-dir=`brew --prefix freetype` \
    --with-gd \
    --with-gettext=`brew --prefix gettext` \
    --with-gmp \
    --with-jpeg-dir=`brew --prefix gd` \
    --with-mcrypt=`brew --prefix mcrypt` \
    --with-mysqli=`brew --prefix`/bin/mysql_config \
    --with-openssl \
    --with-pdo-mysql=`brew --prefix mariadb` \
    --with-png-dir=`brew --prefix gd` \
    --with-zlib=`brew --prefix zlib`
make -j`sysctl -n hw.logicalcpu_max`

Create Package Installer

Now create the package installer and complete the installation via the GUI.

env INSTALL_ROOT=$PWD/phpng-pkg make install
pkgbuild \
    --root phpng-pkg \
    --identifier net.php.phpng \
    --version 7.0.0-dev \
    --ownership recommended \
    phpng-dev.pkg
open phpng-dev.pkg

Use PHPNG

By default OS X will use the PHP binary located at /usr/bin/php, which as of this writing is PHP 5.5. To have PHPNG take precedence, will need to symlink to the /usr/local/bin directory. Run php -v to make sure you have the correct version, and if it’s not what you expected try which php to see the location that is being selected based on your $PATH.

ln -s /usr/local/opt/phpng/bin/php /usr/local/bin
php -v

PHP 7.0.0beta2 (cli) (built: Aug  3 2015 13:22:21) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies

The post Install PHP 7.0 (phpng) on Mac OS X appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/install-php-7-0-phpng-on-mac-os-x/feed/ 5
ACF validate_value Filter With post_ID https://www.justinsilver.com/technology/wordpress/advanced-custom-fields-validate_value-filter-with-post_id/?utm_source=rss&utm_medium=rss&utm_campaign=advanced-custom-fields-validate_value-filter-with-post_id https://www.justinsilver.com/technology/wordpress/advanced-custom-fields-validate_value-filter-with-post_id/#comments Sun, 19 Oct 2014 21:22:18 +0000 http://justinsilver.com/?p=3769 Advanced Custom Forms Pro 5.0 is out, and it contains a major overhaul to the way that custom fields are handled. It also had a major impact on the way that third-party add-ons were...

The post ACF validate_value Filter With post_ID appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

Advanced Custom Forms Pro 5.0 is out, and it contains a major overhaul to the way that custom fields are handled. It also had a major impact on the way that third-party add-ons were written to extend ACF functionality which meant that it was considerable work to refactor my Validated Fields plugin to support the new architecture. The new architecture is definitely superior in my opinion and has some great new filters that we can leverage such as acf/validate_value and its siblings acf/validate_value/type={$field_type}acf/validate_value/name={$field_name}acf/validate_value/key={$field_key}.

Unfortunately this filter does not have the post_ID available to it, which greatly limits the range of things we can do with it. To work around this I found that by inserting a field named acf[post_ID] into the editor form – and the “acf” part is critical – it would be picked up and submitted with the rest of the form values. This meant that it would be available in the $_POST, really opening up the possibilities.

Sample Code

// use a unique value to prevent conflicts with other ACF fields
define( 'MY_ACF_FORM_VALUES', 'MY_ACF_FORM_VALUES' );

// add the post_ID to the acf[] form
function my_edit_form_after_editor( $post ){
	print( "<input type='hidden' name='acf[%1$s][post_ID]' value='%2$d'/>", 
		MY_ACF_FORM_VALUES, 
		$post->ID 
	);
}
add_action( 'edit_form_after_editor', 'my_edit_form_after_editor' );

// use the post_ID in your validation function
function my_validate_value( $valid, $value, $field, $input ) {
	$post_id = $_POST['acf'][MY_ACF_FORM_VALUES]['post_ID'];
	// more code!
	return $valid;
}
add_filter( "acf/validate_value", 'my_validate_value', 10, 4 );

The rest of the my_validate_value() will be up to you.

Shameless Plug.

Why reinvent the wheel? The above code is already included in Validated Field for ACF available in the WordPress repository.

The post ACF validate_value Filter With post_ID appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/wordpress/advanced-custom-fields-validate_value-filter-with-post_id/feed/ 8
Using WP Better Emails with WooCommerce Email Templates https://www.justinsilver.com/technology/wordpress/using-wp-better-emails-woocommerce-email-templates/?utm_source=rss&utm_medium=rss&utm_campaign=using-wp-better-emails-woocommerce-email-templates https://www.justinsilver.com/technology/wordpress/using-wp-better-emails-woocommerce-email-templates/#comments Thu, 24 Jul 2014 22:35:00 +0000 http://justin.ag/?p=3673 On one site that I run there are several different functions, primarily provided by disparate plugins with custom actions/filters, that send emails both to site administrators and customers. For most emails that are sent...

The post Using WP Better Emails with WooCommerce Email Templates appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

On one site that I run there are several different functions, primarily provided by disparate plugins with custom actions/filters, that send emails both to site administrators and customers. For most emails that are sent from WordPress itself and several of the plugins, the content type is set to plain/text allowing me to use WP Better Emails to wrap content in an easily edited header and footer. WooCommerce on the other hand proved to be a little more tricky – there is the option to send emails via plain/text, but they definitely lack valuable formatting when displaying order information to a customer. This is further compounded if you insert any custom HTML into the content.

Conceptually all that needs to be done is to first remove the WooCommerce email header and footer, and second have WP Better Emails process it even though it has a content type of text/html. After checking out the code for both of the plugins in question, I devised a way to make it work.

Remove WooCommerce Email Headers and Footers

If you view the source of any of the WooCommerce email templates (at least the default ones) you will see a line for <?php do_action( 'woocommerce_email_header', $email_heading ); ?> and <?php do_action( 'woocommerce_email_footer' ); ?> which are the hooks that WooCommerce itself uses to insert the header and footer contents. By setting our own functions to these hooks earlier and later than the WooCommerce priorities, we can capture all of the content and hide it with ob_start() and ob_get_clean() to capture and clean the output buffer contents. We are also setting a filter to return true any time the woocommerce_email_header action is run.

Common sense says that we could just unhook all functions from these actions, however in my testing I found that some other, non-UI, logic was being performed in some of the attached functions. This method allows the code to run, but prevents the output from being inserted into the generated email.

Apply WP Better Emails Template

Next we need to apply the email template that WP Better Emails did not, because the content type was wrong – text/html and not text/plain. This is actually a good thing because we also want to avoid some of the formatting that WP Better Emails applies to the typical plain text email content. We can do this using the global $wp_better_emails and hooking into phpmailer_init after most of the work has been done – priority 20 works fine.

This example uses anonymous function which require PHP 5.3+, however you could also use create_function().

// Determine if it's an email using the WooCommerce email header
add_action( 'woocommerce_email_header', function(){ add_filter( "better_wc_email", "__return_true" ); } );

// Hide the WooCommerce Email header and footer
add_action( 'woocommerce_email_header', function(){ ob_start(); }, 1 );
add_action( 'woocommerce_email_header', function(){ ob_get_clean(); }, 100 );
add_action( 'woocommerce_email_footer', function(){ ob_start(); }, 1 );
add_action( 'woocommerce_email_footer', function(){ ob_get_clean(); }, 100 );

// Selectively apply WPBE template if it's a WooCommerce email
add_action( 'phpmailer_init', 'better_phpmailer_init', 20 );
function better_phpmailer_init( $phpmailer ){
	// this filter will return true if the woocommerce_email_header action has run
	if ( apply_filters( 'better_wc_email', false ) ){
		global $wp_better_emails;

		// Add template to message
		$phpmailer->Body = $wp_better_emails->set_email_template( $phpmailer->Body );

		// Replace variables in email
		$phpmailer->Body = apply_filters( 'wpbe_html_body', $wp_better_emails->template_vars_replacement( $phpmailer->Body ) );
	}
}

Success!

Your WP Better Emails templates should now be applied to your WooCommerce emails.

The post Using WP Better Emails with WooCommerce Email Templates appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/wordpress/using-wp-better-emails-woocommerce-email-templates/feed/ 5
Check For WordPress Plugin Updates https://www.justinsilver.com/technology/wordpress/check-wordpress-plugin-updates/?utm_source=rss&utm_medium=rss&utm_campaign=check-wordpress-plugin-updates https://www.justinsilver.com/technology/wordpress/check-wordpress-plugin-updates/#respond Tue, 15 Apr 2014 21:45:51 +0000 http://justin.ag/?p=3458 If you write and contribute plugins to the WordPress Repository then you might be interested in having your plugin be aware of updates you have made available – an admin notice or something similar....

The post Check For WordPress Plugin Updates appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

If you write and contribute plugins to the WordPress Repository then you might be interested in having your plugin be aware of updates you have made available – an admin notice or something similar. Maybe design a clever versioning scheme so that you can inform the user of critical fixes in a more dramatic way than regular patches.

Check For WordPress Plugin Updates

// Your plugin file, perhaps __FILE__?
$plugin_file = 'plugin-name/plugin-file.php';

// Check for Plugin updates, if you want to have the latest (not necessarily recommended)
wp_update_plugins();

// Results of the update check
$update_plugins = get_site_transient( 'update_plugins' );
if ( isset( $update_plugins->response[ $plugin_file ] ) ) {
    // Your plugin needs an update, do something about it?
}

Plugins With Updates

In the result of update_plugins the $update_plugins->response is an array() that will be something like the following, if there is anything else you want to check.

'response' => 
  array (
    'plugin-dir/plugin-file.php' => 
    stdClass::__set_state(array(
       'id' => '12345',
       'slug' => 'plugin-slug',
       'plugin' => 'plugin-name/plugin-file.php',
       'new_version' => '1.2.3',
       'url' => 'https://wordpress.org/plugins/plugin-name/',
       'package' => 'https://downloads.wordpress.org/plugin/plugin-name.1.2.3.zip',
    )),
),

Compare Installed and Available WordPress Plugin Versions

function my_admin_notice() {
    global $my_admin_notice;
    ?>
    <div class="updated">
        <p><?php _e( 'An update is available for your plugin!', 'my-text-domain' ); ?>
        <?php echo $my_admin_notice; ?></p>
    </div>
    <?php
}

function check_update_notices(){
    global $my_admin_notice;
    $plugin_file = 'plugin-name/plugin-file.php';
    $installed_ver = split( ',', $update_plugins->checked[$plugin_file] );
    $available_ver = split( ',', $update_plugins->response[$plugin_file]->new_version );
    $v1 = $installed_ver[0];
    $v2 = $available_ver[0];
    if ( $v1 != $v2 ){
        $behind = $v2-$v1;
        $my_admin_notice = $behind!=1? "Oh no, you're {$behind} major version(s) behind!" : "";
        add_action( 'admin_notices', 'my_admin_notice' );
        return;
    }
}

The post Check For WordPress Plugin Updates appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/wordpress/check-wordpress-plugin-updates/feed/ 0
SIM Card/ICCID Validation https://www.justinsilver.com/technology/sim-card-iccid-validation/?utm_source=rss&utm_medium=rss&utm_campaign=sim-card-iccid-validation https://www.justinsilver.com/technology/sim-card-iccid-validation/#comments Tue, 08 Apr 2014 21:45:37 +0000 http://justin.ag/?p=3390 The Subscriber Identification Module (SIM) Card is an chip that stores your wireless devices’ International Mobile Subscriber Identity (IMSI). The SIM Card is in turn identified by an Integrated Circuit Card Identifier (ICCID) which...

The post SIM Card/ICCID Validation appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

The Subscriber Identification Module (SIM) Card is an chip that stores your wireless devices’ International Mobile Subscriber Identity (IMSI). The SIM Card is in turn identified by an Integrated Circuit Card Identifier (ICCID) which is printed on the card.

I needed to identify valid ICCID values for a project I was working on, and more specifically SIM Cards that are valid on the Verizon LTE network in the United States. The ICCID values we are expecting will be 19 digits + a check digit for a total length of 20 numeric characters. The first two are hard coded to “89” for “telecommunications”, followed by a “1” for the United States country code, and then 3 digits identifying the Verizon Mobile Network Code (MNC) – see the previous link for valid values for other carriers – and then a final check digit using the Luhn algorithm.

In my code I first validate using a regular expression, since the regex should be decently efficient, and then calculate the Luhn check digit to make sure the number itself is correct.

<?php
class SimCardUtils {
	public static function isValidLuhn( $number ){
		// validate luhn checksum
		settype($number, 'string');
		$sumTable = array(
			array(0,1,2,3,4,5,6,7,8,9),
			array(0,2,4,6,8,1,3,5,7,9)
		);
		$sum = 0;
		$flip = 0;
		for ($i = strlen($number) - 1; $i >= 0; $i--) {
			$sum += $sumTable[$flip++ & 0x1][$number[$i]];
		}
		return $sum % 10 === 0;
	}

	public static function isValidSim( $sim_id ){
		// 89       = telecom
		// 1        = united states
		// [480-489] = verizon
		// {13}     = sim account
		// {1}      = luhn check digit
		$pattern = "/^(89)(1)(48[0-9])(\d{13})(\d)$/";

		// check to see if the pattern is valid followed by the Luhn checksum
		return ( false !== preg_match($pattern, $sim_id) && self::isValidLuhn( $sim_id ) );
	}
}
<?php
$iccids = array(
	'89148000000745809013', // valid
	'89148000000745809014', // invalid, wrong check digit
	'8914800000074580901',  // invalid, wrong length
);

foreach ( $iccids as $iccid ){
	echo $iccid . " is " . ( SimCardUtils::isValidSim( $iccid )? "valid" : "invalid" ) . ".\n";
}
89148000000745809013 is valid. 
89148000000745809014 is invalid. 
8914800000074580901 is invalid.

See this in action here http://codepad.viper-7.com/RcIxoH.

The post SIM Card/ICCID Validation appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/sim-card-iccid-validation/feed/ 22
Google Apps + Trac Integration Using email2trac https://www.justinsilver.com/technology/linux/google-apps-trac-integration-using-email2trac/?utm_source=rss&utm_medium=rss&utm_campaign=google-apps-trac-integration-using-email2trac https://www.justinsilver.com/technology/linux/google-apps-trac-integration-using-email2trac/#respond Sun, 09 Jun 2013 08:14:42 +0000 http://justin.ag/?p=3027 I have been using Trac for viewing my Subversion source repository and some ticketing, however I wanted to be able to integrate email directly to the ticketing system. The second part of my setup...

The post Google Apps + Trac Integration Using email2trac appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

I have been using Trac for viewing my Subversion source repository and some ticketing, however I wanted to be able to integrate email directly to the ticketing system. The second part of my setup is the use of Google Apps to host our mail domain, so the easiest way to set this up was to create a new user ([email protected] / p@ssword in the example below).

My development server is running CentOS 5.8, Trac 0.12, and python2.7 (although the site-packages for CentOS are still in /var/lib/python2.4/site-packages. Because of this it was necessary to add the PYTHONPATH to the environment when calling email2trac.

The installation instructions for email2trac can be found on its homepage here, or here’s the quick version:

cd ~
wget ftp://ftp.sara.nl/pub/outgoing/email2trac.tar.gz
tar xvf email2trac.tar.gz
cd email2trac-*
./configure
make
make install

The configuration information for email2trac is located in /usr/local/etc/email2trac.conf. I made a few changes to the default configuration as you can see below, or check out the default configuration.

[DEFAULT]
project: /var/trac/project
debug: 0 
black_list: MAILER-DAEMON@
drop_spam : 1
drop_alternative_html_version: 1
email_quote: >
html2text_cmd:
ignore_trac_user_settings: 0
inline_properties: 1
reply_all : 0
spam_level: 5
strip_quotes: 1
strip_signature: 1
ticket_update: 1
ticket_update_by_subject: 1
umask: 022
verbatim_format: 1

[other_project]
project: /var/trac/other_project

On my system I also needed to do a custom build of MySQL-python to get it into the proper PYTHONPATH. With my default python set to 2.7, I ran the following:

cd ~
yum install php-imap python-devel mysql-devel
wget http://sourceforge.net/projects/mysql-python/files/latest/download
cd MySQL-python*
python setup.py install

Note that above on my system I actually only installed mysql-devel.x86_64 due to a conflict in the i386 version.

Next I used the following PHP script to import message from the Trac Google Apps user and process them into Trac one at a time. Due to the different environment I had to set the PYTHONPATH using putenv() so that email2trac would run. This file was saved as /var/trac/gmail2trac.php.

<?php
// Connect to the Google Apps / Gmail account
$mailbox = imap_open("{imap.googlemail.com:993/ssl}INBOX", "[email protected]", "p@ssword");
// Get all unread emails
$mail = imap_search($mailbox, "UNSEEN");
if ( !empty($mail) ){
        // This is required on CentOS to find the Trac egg
        putenv("PYTHONPATH=/usr/lib/python2.4/site-packages");
        // Process each email
        foreach ($mail as $id){
                // Save the email contents to a temp file
                imap_savebody($mailbox, '/tmp/gmail2trac.txt', $id);
                // Import into Trac via email2trac
                system('/usr/local/bin/email2trac -f /usr/local/etc/email2trac.conf -p project < /tmp/gmail2trac.txt');
                // Mark as read
                imap_setflag_full($mailbox, $id, "\\Seen");
        }
}
// Close connection
imap_close($mailbox);
?>

Note that if you want to reprocess any emails, all you need to do is log in as the Trac user and mark the message as unread.

Lastly to import on a schedule – I opted for a check every 5 minutes – just setup a cron job via crontab -e.

*/5 * * * * php /var/trac/gmail2trac.php

The post Google Apps + Trac Integration Using email2trac appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/linux/google-apps-trac-integration-using-email2trac/feed/ 0
Google Analytics for WordPress Fixed https://www.justinsilver.com/technology/wordpress/google-analytics-for-wordpress-fixed/?utm_source=rss&utm_medium=rss&utm_campaign=google-analytics-for-wordpress-fixed https://www.justinsilver.com/technology/wordpress/google-analytics-for-wordpress-fixed/#comments Fri, 01 Feb 2013 21:56:02 +0000 http://justin.ag/?p=2959 “Unfortunately, an error occurred while connecting to Google” Google Analytics for WordPress is a great plugin by Yoast to make adding Analytics tracking to your WordPress site easy. All was well until Google updated...

The post Google Analytics for WordPress Fixed appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

“Unfortunately, an error occurred while connecting to Google”

Yoast Google Analytics for WordPress

Google Analytics for WordPress is a great plugin by Yoast to make adding Analytics tracking to your WordPress site easy. All was well until Google updated their authentication and authorization APIs, thus breaking the plugin’s ability to load your Google Analytics accounts and properties using your Google credentials via OpenID and OAuth. The error that comes back in this case is "Unfortunately, an error occurred while connecting to Google" but no additional information on what exactly the problem was. It has been broken for some time now, and although you can enter your UA code manually, I decided to just fix the code in question.

In a nutshell Google updated their URLs and transitioned from an XML interface to a JSON RESTful web service. The changes are pretty straightforward, but now require two calls to Google to get both the Analytics Accounts associated with your username/auth token and a second one to get all of the Analytics Properties (though they can be loaded for all properties at the same time by using ~all in place of the account id in the request.

The file to modify lives under /wp-content/plugins/google-analytics-for-wordpress/googleanalytics.php. Here is what the code looks like in my version, currently the latest, at 4.2.8. and starts on line 383 and ends on line 435. Replace the code here with the code below it:

// ... Opening code
	$response  = $gdata->get( 'https://www.google.com/analytics/feeds/accounts/default' );
	$http_code = wp_remote_retrieve_response_code( $response );
	$response  = wp_remote_retrieve_body( $response );

	if ( $http_code == 200 ) {
		$options['ga_api_responses'][$token] = array(
			'response'=> array( 'code'=> $http_code ),
			'body'    => $response
		);
		$options['ga_token']                 = $token;
		update_option( 'Yoast_Google_Analytics', $options );
	}
}

if ( isset( $options['ga_api_responses'][$token] ) && is_array( $options['ga_api_responses'][$token] ) && $options['ga_api_responses'][$token]['response']['code'] == 200 ) {
	$arr = yoast_xml2array( $options['ga_api_responses'][$token]['body'] );

	$ga_accounts = array();
	if ( isset( $arr['feed']['entry'][0] ) ) {
		foreach ( $arr['feed']['entry'] as $site ) {
			$ua      = $site['dxp:property']['3_attr']['value'];
			$account = $site['dxp:property']['1_attr']['value'];
			if ( !isset( $ga_accounts[$account] ) || !is_array( $ga_accounts[$account] ) )
				$ga_accounts[$account] = array();
			$ga_accounts[$account][$site['title']] = $ua;
		}
	} else {
		$ua      = $arr['feed']['entry']['dxp:property']['3_attr']['value'];
		$account = $arr['feed']['entry']['dxp:property']['1_attr']['value'];
		$title   = $arr['feed']['entry']['title'];
		if ( !isset( $ga_accounts[$account] ) || !is_array( $ga_accounts[$account] ) )
			$ga_accounts[$account] = array();
		$ga_accounts[$account][$title] = $ua;
	}
// ... Closing code

The modified code looks like this:

// ... Opening code
	// Get all of the Accounts for this oauth token
	$url = 'https://www.googleapis.com/analytics/v3/management/accounts';
	$response  = $gdata->get( $url );
	$http_code = wp_remote_retrieve_response_code( $response );
	$response  = wp_remote_retrieve_body( $response );

	if ( $http_code == 200 ) {
		$options['ga_api_responses'][$token] = array(
			'acct_response'=> array( 'code'=> $http_code ),
			'acct_body'    => $response
		);

		// Get all of the properties for this oauth token
		$url = 'https://www.googleapis.com/analytics/v3/management/accounts/~all/webproperties/';
		$response  = $gdata->get( $url );
		$http_code = wp_remote_retrieve_response_code( $response );
		$response  = wp_remote_retrieve_body( $response );

		if ( $http_code == 200 ) {
			$options['ga_api_responses'][$token]['response'] = array( 'code'=> $http_code );
			$options['ga_api_responses'][$token]['body'] = $response;

			$options['ga_token']                 = $token;
			update_option( 'Yoast_Google_Analytics', $options );
		}
	}
}

if ( isset( $options['ga_api_responses'][$token] ) && is_array( $options['ga_api_responses'][$token] ) && $options['ga_api_responses'][$token]['response']['code'] == 200 ) {

	// Get all of the accounts so we can reference the name by ID
	$account_info = array();
	$json = json_decode( $options['ga_api_responses'][$token]['acct_body'] );
	foreach ($json->items as $item) {
		$account_id = strval($item->id);
		$account_info[$account_id] = $item->name;
	}

	// Get all of the properties in to an array
	$ga_accounts = array();
	$json = json_decode( $options['ga_api_responses'][$token]['body'] );
	foreach ($json->items as $item) {
		$account_id = strval($item->accountId);
		$account = $account_info[$account_id];
		$ua = $item->id;
		$title = $item->name; 

		// make sure we have an arrary created to hold the properties
		if ( !isset( $ga_properties[$account] ) || !is_array( $ga_properties[$account] ) )
			$ga_accounts[$account] = array();

		// Save the property by account for display
		$ga_accounts[$account][$title] = $ua;
	}
// ... Closing code

The post Google Analytics for WordPress Fixed appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/wordpress/google-analytics-for-wordpress-fixed/feed/ 4
WordPress Plugin: validated-field-for-acf https://www.justinsilver.com/technology/wordpress/wordpress-plugins/wordpress-plugin-validated-field-for-acf/?utm_source=rss&utm_medium=rss&utm_campaign=wordpress-plugin-validated-field-for-acf https://www.justinsilver.com/technology/wordpress/wordpress-plugins/wordpress-plugin-validated-field-for-acf/#comments Sun, 04 Nov 2012 14:23:27 +0000 http://justin.ag/?p=2792 This plugin will create an add-on field wrapper for Advanced Custom Fields (ACF in the WordPress Plugin Repository) that will give you additional validation functionality – PHP functions, regular expression, input field masking, and...

The post WordPress Plugin: validated-field-for-acf appeared first on Justin Silver.

]]>
AmpedSense.OptimizeAdSpot('AP'); AmpedSense.OptimizeAdSpot('IL'); AmpedSense.OptimizeAdSpot('IR');

This plugin will create an add-on field wrapper for Advanced Custom Fields (ACF in the WordPress Plugin Repository) that will give you additional validation functionality – PHP functions, regular expression, input field masking, and uniqueness (post type/meta key, meta key, or site-wide). You can find and install the plugin from the WordPress repository, located at http://wordpress.org/extend/plugins/validated-field-for-acf/.

UPDATED: This plugin is compatible with Advanced Custom Fields 4 & 5

The plugin code

This file is always up to date based on the trunk of the WordPress.org SVN repository.

validated_field.php

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

validated_field_v4.php

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

validated_field_v5.php

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

js/input.js

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

css/input.css

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

The post WordPress Plugin: validated-field-for-acf appeared first on Justin Silver.

]]>
https://www.justinsilver.com/technology/wordpress/wordpress-plugins/wordpress-plugin-validated-field-for-acf/feed/ 6