Category: PHP

  • Freshened up this site…

    In response to the recent PHP vulnerability issue, I spent some time here in this blog site to upgrade my WordPress theme, plugins, WordPress installation itself, and finally, the PHP version.

    One minor issue was encountered after upgrading plugins — Head, Footer and Page Injection plugin began showing parts of some code that I inserted, as plain text in my blog site!! I noticed that the plugin had a notice stating that “php is not allowed in your code (disabled by your theme or a plugin)”. The fix that worked was to head over to the plugin’s settings page (Settings -> Head and Footer) and then go to the ‘Advanced’ tab, and then toggle on the setting labeled as “Enable PHP execution”.

    The PHP version I was using was quite outdated T_T and so upgrading to version 8.0 broke my blog site with the error “there has been a critical error on this website.” Fortunately, the thing that I deactivated first was the exact cause of error: my old, outdated theme! It was “Sparkling” theme, which I hadn’t touched for years. I changed into the Twenty Twenty-Five theme for a fresh look and updated WP code. Thank you, Colorlib for the Sparkling theme — it served me well for several years!

    I feel good after taking the time to update this site. I’ve had this for over a decade now.

  • Get “order” object/details from Thank You page of WooCommerce (WordPress)

    It’s been a long while since I last posted anything related to coding. I haven’t really stopped, but from Android app development, I switched back to PHP. Life has become occupied with other things, but when I do code, it’s in WordPress with WooCommerce. It’s for my online shop.

    In my opinion, WordPress is not the most pleasant platform to use if you’re a developer (after years of MVC coding for Android I find WordPress quite messy), but it’s what I already know. I don’t have time to learn another.

    Today’s code snippet is for customizing the Thank You page (post-checkout) by retrieving the “order” object.

    The $order_id is what we’ll start with. Then we get the order object with the help of the wc_get_order($order_id) method. Once you’re able to successfully call the order object, you may use its methods such as get_billing_first_name() to get the order details.

    You may refer to the WC_Order class page for a list of available methods.

    I originally got this code from Order Received (Thank you) page in WooCommerce and modified it to suit my needs. Check his blog out, as he has many helpful posts on how to customize WooCommerce!

  • Laravel 5.X directory permissions / ownership setup

    According to the Laravel docs, “After installing Laravel, you may need to configure some permissions. Directories within the storage and the bootstrap/cache directories should be writable by your web server or Laravel will not run”.

    After running this command to install Laravel via Composer:

    Change directory ownership by running these commands:

    Then you should see “Laravel 5” on your public folder when you visit it on a web browser.

    Make sure you setup your app key by running php artisan key:generate, or else your Laravel still won’t run!

    Reference: “The permissions for the storage and vendor folders should stay at 775, for obvious security reasons” on File permissions for Laravel 5 (and others)

  • Installing Laravel 5 on Apache in Mac OS X El Capitan

    Last time, I wrote a guide on How to install Laravel 5 in Windows with XAMPP. I’ve been coding more often on Mac computers recently, and now I need to setup Laravel on a MacBook Pro, so I decided I’ll write a guide on how to install Laravel 5 on Mac OS X El Capitan too. 🙂

    First, I’ll assume you already have a local development environment set up on your Mac.

    Environment Requirements

    This guide won’t cover setting up Laravel on Homestead, so let’s make sure our development environment meets the following requirements:

     

    • PHP >= 5.6.4
    • OpenSSL PHP Extension
    • PDO PHP Extension
    • Mbstring PHP Extension
    • Tokenizer PHP Extension

    Install Composer

    See the instructions on the Composer download page on how to install composer.

    After installing, you shall get a file composer.phar in the directory where you ran the installation commands for Composer.

    Make ‘composer’ executable from anywhere

    Right now, if you want to run Composer, you will have to navigate to the folder where you stored composer.phar and run a command like php /usr/local/bin/composer.phar. Let’s make our lives easier by creating an alias, an be able to run Composer simply by typing the composer command. 😉

    Let’s move composer.phar to the path /usr/local/bin by running this command:

    And to finally create the alias, type this command to edit bash_profile:

    Add the following line to your bash_profile:

    Restart terminal or open a new terminal tab. Type composer and this should be able to run Composer.

    Download Laravel via Composer

    Navigate to your document root, (mine is at /webcontent) and run the following command to download and install Laravel into a folder named “laravel5”. Change the folder name as you like.

    Now, I will assume that you have your Laravel at this path: /webcontent/laravel5/

    Verify folder permissions

    Update (2016-10-20): I formed the habit of setting permissions of all my bootstrap/cache/* and storage/* directories to 775 (not 755), which means the owner and group members are granted all rights (read, write, execute). 755 will only grant write access to user, and not group members. The owner of all my Laravel files is my own user (e.g., catzie) and the group owner is _www. My own user and the user called _www are both members of the group _www. Permissions on bootstrap/cache and storage/* is drwxrwxr-x

    The contents of the following directories are required to be writable, otherwise, Laravel will not run:

    • storage
    • bootstrap/cache

    Before I set the directories as writable, when I access my Laravel at http://localhost/laravel5/public, I only get an “Error 500” without any detail. Then after setting proper permissions, my Laravel became accessible.

    We are going to set the permission into 755. Some information about 755:

    Tip: you don’t want to set these folders to 777 because you will make attackers happy when they find out they can write to your files/folders! We want to keep attackers unhappy. 😀

    Set permissions on storage folder

    Let’s navigate to /storage then set the permission of /storage contents to 755 through these commands:

    By the way, the -R in the chmod command affects files and directories recursively. It is equivalent to --recursive. The asterisk * lets the chmod apply the change to all contents of present directory /storage.

    Set permissions on bootstrap/cache folder

    After setting 755 as permission on bootstrap/cache, I still had an error, saying file_put_contents(/webcontent/laravel5/bootstrap/cache/services.php): failed to open stream: Permission denied

    To pass the issue, I ran these commands:

    I don’t know why, but setting it to 755 doesn’t work. When I first set to 777, then reset to 755 though, it works!

    Okay, now I get a different error: file_put_contents(/webcontent/laravel5/storage/framework/views/<someHashedString>.php): failed to open stream: Permission denied

    It seems that my /views folder is not writable. But hey, I already set permissions recursively for contents of storage folder! 🙁

    I decided to try the trick I did earlier with bootstrap/cache, which is first setting to 777 then resetting it into 755:

    First, I set it to 777 then viewed Laravel in my browser. It finally loaded the Laravel home screen. But no, I don’t want to leave the folders under /webcontent/laravel5/storage/ with permission 777 because it can be a security risk. So, I set it back to 755:

    I refreshed my browser and Laravel is still running. Whoohoo! Finally!

    If any of you has an idea why setting to 777 then resetting to 755 works, please let me know through the comments area. 😆

    Update: I realized the right thing to do is chmod all directories under storage with 775 to enable group members to write too. And then, chown the folders from “catzie” to “_www”. Since _www is the user who always needs to write to those folders, just let him own them. :p And here I am hoping that I don’t encounter problems when it’s user “catzie” who’s trying to access those folders and their files.

    Update again: My directories and files are owned by group “staff” but only user “catzie” is member of the group called “staff”. This can be checked by the command id -Gn _www and id -Gn catzie. To add user “_www” to the group staff, I will run the following command:

    This -a(dds) “_www”, which is an object of -t(ype) “user”, to the group “staff”. –source

    Create your first Laravel route

    Now that we are able to load the home/welcome page of Laravel, let’s proceed and create a new route.

    With your favorite text editor, open app/Http/routes.php and add the following code:

    When I visited the URL http://localhost/laravel5/public/ohayou, I got this error:

    When I changed AllowOverride None into AllowOverride All in Apache config file /etc/apache2/httpd.conf, all it did was show me the error file_put_contents(/webcontent/laravel5/bootstrap/cache/services.php): failed to open stream: Permission denied again when accessing http://localhost/laravel5/public/ohayou and even the home page.

    y-u-no

    Y U BRING BACK SAME PROBLEM?!

    Despite being potential security risk, this fixed my problem and allowed me to access the URL http://localhost/laravel5/public/ohayou:

    Err, then I tried to set it back to 755 again…

    And yep, still works! I hope this always works from now on. @_@ lalala~

    Test Laravel with MySQL database

    For us to be ready to develop a web app with Laravel, let’s test one last thing: the connection to database. In this section, we’ll use Artisan to run “migrations”.

    Artisan is the command line interface that’s included in Laravel. And when we run migrations, tables are created based on schemas defined in the migrations in the directory /webcontent/laravel5/database/migrations.

    Create database

    I’ll be using Terminal to check MySQL. If you prefer PhpMyAdmin, that’s okay.

    Create a database named “laravel5”:

    Then select that database:

    You’ll see that there are no tables yet, since we only just created the database without adding any table:

    Change database settings on .env file

    When I finished installing Laravel, a .env file was generated for me. In case your installation only has a .env.example file, copy that into a new file that’s named .env

    Now that you have a .env file, go ahead and edit it and fill in the correct values for your database connection. Do change the value of the following:

    Run migration

    Laravel’s pre-made migration files will create tables for us, such as the “users” table.

    Run this so that the migrations create database tables:

    Oops, I got an error again: PHP Fatal error: Uncaught exception 'UnexpectedValueException' with message 'The stream or file "/webcontent/laravel5/storage/logs/laravel.log" could not be opened: failed to open stream: Permission denied' in /webcontent/laravel5/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php:107

    Ohhh, I checked the details about the file laravel.log located at /webcontent/laravel5/storage/logs and this is what I found:

    I believe that laravel.log is generated by Laravel… which means that the user laravel uses is _www and not MY user. But we are at the same “group”. Maybe the right thing to do is simply add “write” permission to “group”.

    Lemme try that with this command…

    And now, this is what my laravel.log looks like:

    Whoa, it worked! retried my php artisan migrate and the command ran successfully. 😀

    Check if tables are created

    Back to the MySQL command line, I’m running these commands to check if tables have been created:

    There you have it! Laravel can connect to your MySQL database. 🙂

    Command reference:

    To create new user and grant it all privileges to an existing database, use this:

    Possible hiccups and solutions/workaround

    No supported encrypter found when running php artisan route:list

    When I run the command php artisan route:list to get a list of my Laravel routes, I got the error:

    To fix this, make sure you have a .env file in your Laravel root directory. If you don’t, copy and rename from .env.example then edit the values as needed.

    Then, run this on your Terminal: php artisan key:generate which should generate and save a key on your .env file.

    If that still doesn’t work, maybe it has something to do with the cipher you are using. Edit config/app.php and set the value of cipher to 'AES-256-CBC' so that you have 'cipher' => 'AES-256-CBC',

    Now try to run php artisan route:list again.

    Explanation:

    For Laravel 5.1, if the .env file does not exist, duplicate the .env.example file, rename it to .env, then run php artisan key:generate (as opposed to hardcoding a default in the config/app.php file).
    The artisan command should update the APP_KEY in the .env file with a 32 character string to match the length expected by the ‘cipher’ => ‘AES-256-CBC’ (in the config/app.php file).
    Source: No supported encrypter found. The cipher and / or key length are invalid.

    PDOException when running php artisan migrate

    I wanted to run php artisan migrate in Laravel to generate by database tables but I was getting this error:

    What fixed this issue for me was changing DB_HOST value in .env from ‘localhost’ to ‘127.0.0.1’. This is a known issue in my Mac. I need to use 127.0.0.1 in web app settings to use the database. Hope I find time to fix it 😆

    Reference(s):
    Add a user to the admin group via command line
    Setting folders as writable in Unix systems
    Installing Composer on OS X
    CHMOD settings
    Making some Laravel folders writable

  • PHP: Parse Dates in CSV with inconsistent date formats

    A friend was having trouble with a CSV file that she needs to process via PHP before saving to database. The CSV files uploaded to the server have inconsistent date formats such as:

    So I prepared a PHP script that lists possible date formats in an array $possible_date_formats and then iterates through the dates read from the CSV file, matching each against the date formats in the array.

    Assuming you have a .csv file with tab-delimited data such as this:

    My PHP file will output this when it’s run:

    And below is the PHP file I’m talking about.

  • Laravel 5: create route group that is only available during testing (Middleware)


    Today I needed to protect a group of routes from everything except my testing environment. I need to run PHPUnit tests that depend on certain routes, but I don’t want those routes to be available anywhere else. I’ll share in this blog post what I did to get what I need.

    Assumptions in this tutorial:

    You already have Laravel 5 installed on your computer and you are running the app in “testing” mode (e.g. PHPUnit testing)

    Introduction

    In Laravel, Middleware filters requests that are coming into our application. One of the pre-made Middleware in Laravel 5.2 is Authenticate, which looks like this:

    Inside the handle() method, it checks if the request is using AJAX -or- is asking for JSON, and if either condition returns TRUE, it blocks access and returns ‘Unauthorized’ as response. Otherwise, client is redirected to the ‘login’ route, which should happen when client is requesting via web browser.

    What I did to make my grouped routes available only in testing environment (in my case, when running PHPUnit) was create a new Middlewave. I’ll show you how. 🙂

    Create a new file under Http/Middleware and name it TestingEnvOnly.php

    In the handle method, we check if app environment is set to testing, and if so, we allow the request to access the requested route. Otherwise, the request should fail and repond with ‘Unavailable’.

    Now, let’s register this Middleware to Http/Middleware. Add the following to the $routeMiddleware array:

    It’s time to add a testing-only route:

    If you use PHPUnit like I do, you can test our new Middleware by creating this test method:

    I’m only using var_dump so that we can easily see the printed string response which should say “This should be visible only for testing environment” when you run PHPUnit.

    Now, in your web browser, visit the route your set for /api/v1/testing_env_only. It should say ‘Unauthorized’.

    Here’s how the files I edited in Laravel look like now:

    I’m using Laravel 5.2 and these are codes I uploaded at Gist

  • Laravel 5: activate API token guard and print “Unauthorized” instead of login redirect

    In Laravel 5, I wrap my API routes in a route group like this:

    Notice that I use auth:api and throttle on my middleware array.

    auth:api turns on the auth middleware with API token as guard, while throttle activates rate limiter for APIs.

    To get started with API token authentication, you may read https://gistlog.co/JacobBennett/090369fbab0b31130b51.

    I followed the same tutorial to set mine up, but had this issue: Upon using invalid api_token or no token at all, I am redirected to the /login route, which in my case is a currently nonexistent route.

    As instructed by the guide, I already edited my app/Http/Middleware/Authenticate.php file to add the || $request->wantsJson() condition, but my API routes still redirected to /login route upon detection of invalid api_token.

    The solution

    What I did was add another condition: || $guard == "api"

    And now, my app/Http/Middleware/Authenticate.php file looks like this:

  • Laravel 5 RESTful API with Basic Auth: PHPUnit Testing

    I’ve been using PHPUnit to test my RESTful API. PHPUnit is ready to use in Laravel.

    In my Laravel-based RESTful API, I have an endpoint /api/users which returns JSON data when you send a GET request. The API will only return such data if the client sends the corrent username and password (Basic Authentication). The JSON data looks like this:

    I’m gonna show you how to create a PHPUnit test for this kind of JSON API data in Laravel 5.

    To create a test case, use this command:

    This will create a new test case named ApiUsersTest.php in your directory /tests

    Paste the following code in it.

    Edit the test case as needed.

  • Laravel update from v.5.0.35 to v.5.2.32 hiccups and solutions

    I tried to update Laravel 5 today and here were the steps I had to take.

    First checked my Laravel version before the update:

    Edited composer.json in my laravel’s root folder like such:

    Run this on command line:

    You might need to delete root folder’s composer.lock file before the update can actually begin.

    I got an error which I later fixed. Scroll to the bottom of the following message.

    So, Illuminate\Routing\ControllerServiceProvider’ could not be found.

    What I did was remove the following line from config/app.php:

    New error upon running php artisan –version:

    I created a folder named “cache” under bootstrap folder to solve that one.

    Tried to check my Laravel version again, but this was the new error:

    Solution was this:

    Then, finally!

    Oops, I can’t view my Laravel site on the web browser. It gives the following error:

    I opened App/Http/Controllers/Controller.php and replaced all instances of DispatchesCommands with DispatchesJobs.

    Next web browser error:

    So I replaced the content of my config/auth.php file with the following:

    Another error… Oh will this end soon?

    …which was caused by this code in my blade file:

    I simply passed a string “/” to the url() method to fix it. Then, ta-da! I could browse my Laravel site again via web browser.

  • Laravel 5: Create controller under new folder and routing

    So here I am on a Sunday, trying to make progress with a personal Laravel 5 site I need to work on. As I bear with the noise outside in the street (some crazy neighbors set up a swimming pool IN THE STREET! :oops:), I’m trying to figure out how too create a new Laravel 5 controller and place it inside a sub-folder.

    Thanks to a StackOverflow answer as my guide, it’s now working. Here, I’ll share how I did it. Just replace “New” with whatever name you want.

    First, create NewController.php on this folder: app\Http\Controllers\New\

    Then the first part of the code should be like:

    My call for the blade file in index() looks like this:

    In app\Http\routes.php, add this:

    $router->get(‘/new’, ‘New\PostsController@index’);

    Last, run composer dump-autoload or php artisan dump

    Guide: Laravel Controller Subfolder routing