Scripting

Ramblings and links to interesting snippets


Fastest method for Javascript substring search

I have a mobile application that needs to search through a rather large array and I’m experiencing some optimization issues with it.  So, I decided to run some tests to see which function would be the fastest between indexOf, search, and includes.

I first tested all three with a static search value, search performed the best:

test1

But, with a variable, indexOf performed the best:

test2

I was able to perform these tests pretty easily using https://jsperf.com/ :)

Permalink » No comments

nodejs with cygwin

I keep having to redo this, so I’m coping down the trick from this article here, so I can find in the future.  To get NPM and NodeJS to work in cygwin on windows, you just have the alias them using these commands in your .bash_profile:

1
2
alias npm="/cygdrive/p/Programs/nodejs/npm.cmd"
alias node="/cygdrive/p/Programs/nodejs/node.exe"

Permalink » No comments

Email Monthly Spreadsheet Reports from WordPress

I’ve been working on a project where we have a very custom Customer Service form and we wanted to start sending out monthly excel reports with all the issues from the past month.

The form is a bit too custom to switch over to a plugin, so I opted to do the set-up by hand.  At the start the form was only sending out emails. So first I needed to create a custom post type to hold all the responses.  you can create one by adding the following code to your functions.php file.  WordPress has a breakdown of all the arguments in their documentation.

1
2
3
4
5
6
7
8
9
10
11
//Support Content Type
$args = array(
    'label'              => 'Support Request',
    'show_ui'             => true,
    'show_in_admin_bar'   => false,
    'public'              => false,
    'menu_position'       => 25,
    'menu_icon'           => 'dashicons-editor-help',
    'supports'            => array( 'title','editor','custom-fields')
);
register_post_type( 'support_request', $args );

Next, I needed to add in the following after sending the email off on the custom form page.  I’m setting the post title and post message to be identical to the email title and body that’s already been generated by the form.  I’m also adding in two custom fields “name” and “email.”  Those are just for example, you can add as you like and your form will likely dictate those.

1
2
3
4
5
6
7
8
9
//add to support request content type
$postarr = array(
    'post_title' => $title,
    'post_content'=> $message,
    'post_type' => 'support_request'
);
$post_id = wp_insert_post( $postarr );
update_post_meta($post_id,'Name',$_REQUEST['customer-name']);
update_post_meta($post_id,'Email',$_REQUEST['customer-email']);

After that, I created a page to generate the excel file.  I created a custom “generate_customer_report_excel.php” in my theme’s directory so it wouldn’t fatten up my functions.php file.  I’m going to create the filename ($output_filename) in the functions.php file to keep things DRY. If you want a frequency different then 30 days, you’ll need to change the “‘after’ => ‘- 30 days‘” line. You will also need to create a “support_requests” folder in your uploads folder. Here’s an example of what that page looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//build your query 
$args = array(
    'post_type' => 'support_request',
    'post_status' => array('publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit'),
    'posts_per_page' => -1,
    'date_query'    => array(
        'column'  => 'post_date',
        'after'   => '- 30 days'
    )
);
 
query_posts($args);
 
// Prepare our csv download
$output_handle = fopen(WP_CONTENT_DIR . '/uploads/support_requests/'.$output_filename ,"w");
 
// Insert header row
fputcsv( $output_handle, ['Name','Email','Message']);
 
// The Loop
while ( have_posts() ) : the_post();
    $id = get_the_ID();
    $row = array(
        get_post_meta( $id, 'Name', false )[0],
        get_post_meta( $id, 'Email', false )[0],
        get_the_content()
    );
    fputcsv( $output_handle, $row);
endwhile;
if(!have_posts()){fputcsv( $output_handle, ['No Support Requests']);}
 
// Close output file stream
fclose( $output_handle );

Finally, I want to use WP Cron to set a monthly cron job to send out the email with the CSV attached.  To change the interval you’ll need to change the “‘interval’ => 2592000,”  and “$DownloadReportFrom = date(‘m_d_Y’,strtotime(“-1 month”));” to be the time span you want. Also, you’ll definaly need to adjust the to and from emails within the support_monthly_report function. This is the code to go in the functions.php file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//Support Question reports
function my_cron_schedules($schedules){
    if(!isset($schedules["monthly"])){
        $schedules["monthly"] = array(
            'interval' => 2592000,
            'display' => __('Once a month'));
    }
    return $schedules;
}
add_filter('cron_schedules','my_cron_schedules');
 
add_action('init','support_monthly_report_schedule');
add_action('support_monthly_report_job','support_monthly_report');
 
function support_monthly_report_schedule(){
    if (!wp_next_scheduled ( 'support_monthly_report_job' )) {
        wp_schedule_event(time(), 'monthly', 'support_monthly_report_job');
    }
}
 
function support_monthly_report(){
    $email = 'TOEMAIL';
    $subject = 'Monthly Report';
    $message = 'EMAILBODY';
 
    $DownloadReportFrom = date('m_d_Y',strtotime("-1 month"));
    $DownloadReportTo = date('m_d_Y',strtotime("now"));
    $output_filename = 'Support_report-' . $DownloadReportFrom .'-'. $DownloadReportTo  . '.csv';
 
    include('generate_customer_report_excel.php');
    usleep(300000);
    $attachments = array( WP_CONTENT_DIR . '/uploads/support_requests/'.$output_filename );
    $headers = 'From: FROMNAME ' . "\r\n";
 
    wp_mail($email,$subject, $message, $headers, $attachments );
}

And that should do it! You’ll be sending snazzy spreadsheets out in no time 😀

Permalink » No comments

Load balancing with WHM, NGINX, and mirrors

I have a project where I need to do a bit of load balancing to keep a website online for a very small window of time when it would receive an extremely high level of traffic.  I saw a dramatic increase in performance after simply installing NGINX, but I also wanted to be able to use mirrors and change the split of traffic during that peak time if we experienced any issues. NGINX does have a module for setting up upstream proxies to handle load balancing, but for this project redirects were simpler and more flexible.

This does only apply to virtual private servers or dedicated hosting – you won’t be able to run this kind of setup in a shared hosting environment.  Start by installing NGINX, below I have instructions on how to add NGINX if your site is on CPanel.

  1. cd /usr/local/src
  2. wget http://nginxcp.com/latest/nginxadmin.tar
  3. tar -xf nginxadmin.tar
  4. cd publicnginx
  5. ./nginxinstaller install

You will also need to delete the automatically generated vhost file for the domain/subdomain you want to change.  And you’ll need to re-delete it if your ever regenerate the vhosts.  You can do this by:

  1. cd /etc/nginx/vhosts/
  2. rm sub.domain.com

NGINX comes pre-installed with the split clients module.  This module is specifically designed for A/B testing, but it will also allow you to split up your traffic between different sites and allow you to adjust how much traffic each site receives.  If you’re using NGINX CP as I described above then you can either edit you NGIX config in WHM, or you can find the file at “/etc/nginx/nginx.conf” to edit from the shell.  In my example below I am also using the $http_referer variable to set-up a separate redirect specifically for direct traffic.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
http {
 
split_clients "${remote_addr}" $mirror {
	33%	"http://google.com";
	33%	"http://yahoo.com";
	*	"http://bing.com";
}
 
server {
	listen 0.0.0.0:80;
	listen [::]:80;
	server_name sub.domain.com www.sub.domain.com;
 
	location / {
		add_header X-Cache "Redirect load balancing";
 
		if ($http_referer = "") {
			set $mirror "http://duckduckgo.com";
		}
 
		return 302 $mirror;
	}
}
 
}

REFERENCES

http://www.nginxcp.com/installation-instruction/
http://nginx.org/en/docs/http/ngx_http_split_clients_module.html
https://www.digitalocean.com/community/tutorials/how-to-target-your-users-with-nginx-analytics-and-a-b-testing
http://serverfault.com/questions/597671/load-balancing-in-nginx-with-redirect-rather-than-proxy

Permalink » No comments

Global Replace Content in RoR

I think it’s fairly typical to have to make a global replace on your database at some time or another – updating old links, old code, ect.  And today this was something I was tasked with!  It was pretty straight forward, and these two stackoverflow questions helped me do it.  To get this working you should just need to follow the commands below, while replacing the following:

  • TABLE – The database table you’re replacing content in
  • COLUMN – The column in that table you’re replacing content in
  • BAD – The old string you want to replace
  • GOOD – The new string you want to replace BAD with
1
2
3
4
5
6
7
8
9
10
rails c
 
ActiveRecord::Base.connection.execute(%q{
    update TABLE
    set COLUMN = replace(
        COLUMN,
        'BAD',
        'GOOD'
    )
})

Checking for a string

You could also use the following code to check whether or not the string exists in any entries in that model in the first place. Just swap out MODEL for the model, SEARCH for the string you want to check, and COLUMN for the column you want to search. It will output the total number of entries containing that string, and then loop through their ID numbers.

1
2
3
4
5
6
7
8
9
10
11
rails c
 
a = MODEL.where("COLUMN like ?", "%SEARCH%");0
 
puts a.length
 
puts " "
 
a.all.each do |a|
  puts a.id
end;0

Permalink » No comments