MacLochlainns Weblog

Michael McLaughlin's Technical Blog

Site Admin

Archive for the ‘LAMP’ Category

Java & MySQL 8.0.19

without comments

It’s the in-between term time and we’re all stuck at home. I decided to update the image for my Fedora 30 virtual machine. I had a work around to the update issue that I had encountered last October in Bug #96969 but it was not required with the current version. However, after updating from MySQL 8.0.17 to MySQL 8.0.19, I found that my Java connection example failed.

The $CLASSPATH value was correct:

/usr/share/java/mysql-connector-java.jar:.

The first error that I got was the my reference to MySQL JDBC driver was incorrect. The error message is quite clear:

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
Cannot connect to database server:
The server time zone value 'MDT' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specifc time zone value if you want to utilize time zone support.

I changed the MySQL Driver reference as instructed by the error message:

29
30
31
      // Create instance of MySQLDriver.
      Class.forName ("com.mysql.cj.jdbc.Driver").newInstance();
      conn = DriverManager.getConnection (url, username, password);

After the change, I got the following error while retesting my little MySQL Java driver connection test program. Initially, I thought this required a change in the Java environment but that wasn’t it.

Cannot connect to database server:
The server time zone value 'MDT' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the 'serverTimezone' configuration property) to use a more specifc time zone value if you want to utilize time zone support.

It required me to add the following line to my /etc/my.cnf configuration file, which synchronizes the database’s timezone with the operating system.

# Synchronize the MySQL clock with the computer system clock.
default-time-zone='+00:00'

Then, running my MySQL Driver connection test program worked like a charm. It returns the following:

Database connection established
MySQLDriver Version [8.0.19]
Database connection terminated

Here’s the MySQL Connector Java code if you’d like to use the MySQLDriver.java 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Import classes.
import java.sql.*;
 
/* You can't include the following on Linux without raising an exception. */
// import com.mysql.jdbc.Driver;
 
public class MySQLDriver {
  public MySQLDriver() {
    /* Declare variables that require explicit assignments because
       they're addressed in the finally block. */
    Connection conn = null;
    Statement stmt = null;
    ResultSet rset = null;
 
    /* Declare other variables. */
    String url;
    String username = "student";
    String password = "student";
    String database = "studentdb";
    String hostname = "localhost";
    String port = "3306";
    String sql;
 
    /* Attempt a connection. */
    try {
      // Set URL.
      url = "jdbc:mysql://" + hostname + ":" + port + "/" + database;
 
      // Create instance of MySQLDriver.
      Class.forName ("com.mysql.cj.jdbc.Driver").newInstance();
      conn = DriverManager.getConnection (url, username, password);
 
      // Query the version of the database.
      sql = "SELECT version()";
      stmt = conn.createStatement();
      rset = stmt.executeQuery(sql);
 
      System.out.println ("Database connection established");
 
      // Read row returns for one column.
      while (rset.next()) {
        System.out.println("MySQLDriver Version [" + rset.getString(1) + "]"); }
 
    }
    catch (SQLException e) {
      System.err.println ("Cannot connect to database server:");
      System.out.println(e.getMessage());
    }
    catch (ClassNotFoundException e) {
      System.err.println ("Cannot find MySQL driver class:");
      System.out.println(e.getMessage());
    }
    catch (InstantiationException e) {
      System.err.println ("Cannot instantiate class:");
      System.out.println(e.getMessage());
    }
    catch (IllegalAccessException e) {
      System.err.println ("Illegal access exception:");
      System.out.println(e.getMessage());
    }
    finally {
      if (conn != null) {
        try {
          rset.close();
          stmt.close();
          conn.close();
          System.out.println ("Database connection terminated");
        }
        catch (Exception e) { /* ignore close errors */ }
      }
    }
  }
  /* Unit test. */
  public static void main(String args[]) {
    new MySQLDriver();
  }
}

As always, I hope this helps those who encounter similar problems.

Written by maclochlainn

April 10th, 2020 at 12:42 pm

PostgreSQL Creating Schema

without comments

The process of creating a schema requires you grant the CREATE ON DATABASE privilege to the user as the postgres user. You use the following syntax:

GRANT CREATE ON DATABASE videodb TO student;

As the student user, you create the app schema with the following syntax:

CREATE SCHEMA app;

Then, you can query the result as follows:

SELECT   * 
FROM     pg_catalog.pg_namespace
ORDER BY nspname;

You should see the following:

      nspname       | nspowner |               nspacl                
--------------------+----------+-------------------------------------
 app                |    16390 | 
 information_schema |       10 | {postgres=UC/postgres,=U/postgres}
 pg_catalog         |       10 | {postgres=UC/postgres,=U/postgres}
 pg_temp_1          |       10 | 
 pg_toast           |       10 | 
 pg_toast_temp_1    |       10 | 
 public             |       10 | {postgres=UC/postgres,=UC/postgres}
(7 rows)

If you create a revision_history table without a schema name, it is automatically placed in the public schema, which means an attempt to describe the table will return an error. For example, you create a revision_history table with the following command:

CREATE TABLE app.revision_history
( revision_history_id serial
, session_id          VARCHAR
, TABLE_NAME          VARCHAR
, revision_id         INTEGER );

You describe the revision_history table with the following command:

\d revision_history

It will show the following because there is no revision_history table in the public schema and the default search path only include a schema that shares the name with the student user and the public schema.

Did not find any relation named "revision_history".

You can show the search path with the following:

show search_path;

It should return the following, which is a schema that shares the user’s name and public.

   search_path   
-----------------
 "$user", public
(1 row)

You set the search path as follows:

SET search_path TO app, "$user", public;

After you set the search_path, a standard attempt to describe the table will find the table whether it is in the app or public schema. That means the following command:

\d revision_history

Shows:

                                                  Table "app.revision_history"
       Column        |       Type        | Collation | Nullable |                            Default                            
---------------------+-------------------+-----------+----------+---------------------------------------------------------------
 revision_history_id | integer           |           | not null | nextval('revision_history_revision_history_id_seq'::regclass)
 session_id          | character varying |           |          | 
 table_name          | character varying |           |          | 
 revision_id         | integer           |           |          |

As always, I hope this helps somebody looking for an answer.

Written by maclochlainn

December 10th, 2019 at 9:37 pm

PostgreSQL Upsert Intro

with one comment

Oracle and SQL Server use the MERGE statement, MySQL uses the REPLACE INTO statement or ON DUPLICATE KEY, but PostgreSQL uses an upsert. The upsert isn’t a statement per se. It is like MySQL’s INSERT statement with the ON DUPLICATE KEY clause. PostgreSQL uses an ON CONFLICT clause in the INSERT statement and there anonymous block without the $$ delimiters.

The general behaviors of upserts is covered in the PostgreSQL Tutorial. It has the following prototype:

INSERT INTO TABLE_NAME(column_list) VALUES(value_list)
ON CONFLICT target action;

The target can be a column name, an ON CONSTRAINT constraint name, or a WHERE predicate, while the action can be DO NOTHING (or ignore) or a DO UPDATE statement. I wrote the following example to show how to leverage a unique constraint with a DO NOTHING and DO UPDATE behavior.

My example conditionally drops a table, creates a table with a unique constraint, inserts a few rows, updates with a DO UPDATE clause, updates with DO NOTHING clause, and queries the results with a bit of formatting.

  1. Conditionally drop the test table.

    /* Suppress warnings from the log file. */
    SET client_min_messages = 'error';
     
    /* Conditionally drop table. */
    DROP TABLE IF EXISTS test;

  2. Create the test table.

    /* Create a test table. */
    CREATE TABLE test
    ( test_id      SERIAL
    , first_name   VARCHAR(20)
    , middle_name  VARCHAR(20)
    , last_name    VARCHAR(20)
    , updated      INTEGER DEFAULT 0
    , update_time  TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
    , CONSTRAINT test_uq_key UNIQUE (first_name,middle_name,last_name));

  3. Insert six rows into the test table.

    /* Insert six rows. */
    INSERT INTO test
    ( first_name, middle_name, last_name )
    VALUES
     ('Harry','James','Potter')
    ,('Ginerva','Molly','Potter')
    ,('Lily','Luna','Potter')
    ,('Albus','Severus','Potter')
    ,('James',NULL,'Potter')
    ,('Lily',NULL,'Potter');

  4. Create a five second delay.

    /* Sleep for 5 seconds. */
    DO $$
    BEGIN
      PERFORM pg_sleep(5);
    END;
    $$;

  5. Use the INSERT statement with a DO UPDATE clause that increments the updated column of the test table.

    /* Upsert on unique key constraint conflict. */
    INSERT INTO test
    ( first_name
    , middle_name
    , last_name )
    VALUES
    ('Harry'
    ,'James'
    ,'Potter')
    ON CONFLICT ON CONSTRAINT test_uq_key
    DO
      UPDATE
      SET    updated = excluded.updated + 1
      ,      update_time = CURRENT_TIMESTAMP;

  6. Use the INSERT statement with a DO NOTHING clause.

    /* Upsert on unique key constraint ignore update. */
    INSERT INTO test
    ( first_name
    , middle_name
    , last_name )
    VALUES
    ('Harry'
    ,'James'
    ,'Potter')
    ON CONFLICT ON CONSTRAINT test_uq_key
    DO NOTHING;

  7. Query the test table.

    /* Formatted query to demonstrate result of UPSERT statement. */
    SELECT   test_id
    ,        last_name || ', '
    ||       CASE
               WHEN middle_name IS NOT NULL THEN first_name || ' ' || middle_name
               ELSE first_name
             END AS full_name
    ,        updated
    ,        date_trunc('second',update_time AT TIME ZONE 'MST') AS "timestamp"
    FROM     test
    ORDER BY last_name
    ,        first_name
    ,        CASE
               WHEN middle_name IS NOT NULL THEN middle_name
               ELSE 'A'
             END;

    Display results:

     test_id |       full_name       | updated |      timestamp      
    ---------+-----------------------+---------+---------------------
           4 | Potter, Albus Severus |       0 | 2019-11-24 19:23:10
           2 | Potter, Ginerva Molly |       0 | 2019-11-24 19:23:10
           1 | Potter, Harry James   |       1 | 2019-11-24 19:23:15
           5 | Potter, James         |       0 | 2019-11-24 19:23:10
           6 | Potter, Lily          |       0 | 2019-11-24 19:23:10
           3 | Potter, Lily Luna     |       0 | 2019-11-24 19:23:10
    (6 rows)

As always, I hope this helps those looking for clear examples to solve problems.

Written by maclochlainn

November 24th, 2019 at 7:26 pm

mysqli Strict Standards

with 2 comments

Six years ago I wrote a common lookup post to illustrate the effectiveness of things used throughout your applications. Now, I’m updating my student image with a more complete solution to show how to avoid update anomalies.

In the prior post, I used a while loop in PHP, like the following:

do {
      ...
} while($stmt->next_result());

Using PHP Version 7.3.8 and MySQL 8.0.16, that now raises the following error message:

Strict Standards: mysqli_stmt::next_result(): There is no next result set. Please, call mysqli_stmt_more_results()/mysqli_stmt::more_results() to check whether to call this function/method in /var/www/html/app/library.inc on line 81

You can see this type of error when you set the following parameters in your file during testing:

ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(E_ALL);

You can read more about error handling at this web page. The new and strict compliance standard for mysqli managing rows is:

do {
      ...
} while($stmt->more_result());

As always, I hope this helps those looking for an answer.

Written by maclochlainn

September 14th, 2019 at 10:30 pm

Posted in LAMP,MySQL,MySQL 8,mysqli,PHP

Tagged with ,

MySQL Update in mysqli

without comments

Somebody didn’t like the MySQLi Update Query example on the tutorialspoint.com website because it use the procedure mysqli_query style. Here’s a simple example of using the object-oriented method version. More or less, instead of query it uses the more intuitive execute() method.

The update_member function contains the logic and below it is a call to the test the function. It relies on a MySQLCredentials.inc file that contains the hostname, user name, password, and database name. You can create create member table, like my example in MySQL 8, or any other table in your MySQL database.

<?php
/*
||  Function Name: update_member
*/
function update_member($account_number, $member_type, $credit_card_number, $credit_card_type) {
 
  // Include the credentials file if omitted.
  include_once("MySQLCredentials.inc");
 
  // Assign credentials to connection.
  $mysqli = new mysqli(HOSTNAME, USERNAME, PASSWORD, DATABASE);
 
  // Check for connection error and print message.
  if ($mysqli->connect_errno) {
    print $mysqli->connect_error."<br />";
    print "Connection not established ...<br />";
  }
  else {
    // Initial statement.
    $stmt = $mysqli->stmt_init();
 
    /* Disabling auto commit when you want two or more statements executed as a set.
    || ------------------------------------------------------------
    ||  You would add the following command to disable the default
    ||  of auto commit.
    ||  ------------------------------
    ||   $mysqli->autocommit(FALSE);
    || ------------------------------------------------------------
    */
 
    // Declare a static query.
    $sql = "UPDATE   member\n"
         . "SET      member_type = ?\n"
         . ",        credit_card_number = ?\n"
         . ",        credit_card_type = ?\n"
         . "WHERE    account_number = ?\n";
 
    /* Prepare statement.
    || ------------------------------------------------------------
    ||  Please note that the bind_param method is a position 
    ||  rather than named notation, which means you must provide
    ||  the variables in the same order as they are found in
    ||  the defined $sql variable as "?".
    || ------------------------------------------------------------
    ||  print($sql);
    ||  print("Member Type:      [1][".$member_type."]\n");
    ||  print("Credit Card No:   [2][".$credit_card_number."]\n");
    ||  print("Credit Card Type: [3][".$credit_card_type."]\n");
    ||  print("Account Number:   [4][".$account_number."]\n");
    || ------------------------------------------------------------
    */
    if ($stmt->prepare($sql)) {
      $stmt->bind_param("ssss",$member_type,$credit_card_number,$credit_card_type,$account_number); } 
 
    // Attempt query and exit with failure before processing.
    if (!$stmt->execute()) {
 
      // Print failure to resolve query message.
      print $mysqli->error."<br />";
      print "Failed to resolve query ...<br />";
    }
    else {   
      /*  Manually commiting writes when you have disabled the
      ||  default auto commit setting, explained above.
      || ------------------------------------------------------------
      ||  You would add the following command to commit the 
      ||  transaction.
      ||  ------------------------------
      ||   $mysqli->commit();
      || ------------------------------------------------------------
      */
    }
  }
}
 
// Test case
update_member('US00011', '1006', '6011-0000-0000-0078', '1007');
?>

I put this logic in a function.php file. If you do the same, you can run the test case like this from the command line:

php function.sql

As always, I hope this helps.

Written by maclochlainn

September 14th, 2019 at 6:20 pm

Django on Fedora 30

without comments

It seemed opportune to add Django to the Fedora 30 instance that I build and maintain for my students. Here are the instructions, which I developed with the prior Fedora 28/29 instructions.

  1. Check your Python3 installation with the following command:

    python3 -V

    It should return this but if it doesn’t you should install python3:

    Python 3.7.4

  2. Check whether pip3 is installation by installing it when its not:

    sudo def -y install python3-php

    It should return:

    Last metadata expiration check: 0:44:52 ago on Tue 10 Sep 2019 11:02:33 AM MDT.
    Package python3-pip-19.0.3-3.fc30.noarch is already installed.
    Dependencies resolved.
    Nothing to do.
    Complete!

  3. Check whether Django is installation by installing it when its not with pip3 installation utility:

    sudo pip3 install --user Django

    It should return the following if installed:

    Requirement already satisfied: Django in /usr/lib/python3.7/site-packages (2.1.10)
    Requirement already satisfied: pytz in /usr/lib/python3.7/site-packages (from Django) (2018.5)

  4. Check your django-admin account location with the which utility:

    which django-admin

    It should return the following on Fedora 30 when installed:

    /usr/bin/django-admin

  5. Create a Django test application with the django-admin utility by creating a project directory. My directory is a bit deep. For reference, it is:

    /home/student/Code/python/django/projects

    Change to that projects directory, and run the following command:

    django-admin startproject test_app

    After that command change directory with the cd command into the test_app subdirectory in your projects directory. Run the manage.py program with the following command:

    python3 manage.py migrate

    You should see the following:

    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, sessions
    Running migrations:
      Applying contenttypes.0001_initial... OK
      Applying auth.0001_initial... OK
      Applying admin.0001_initial... OK
      Applying admin.0002_logentry_remove_auto_add... OK
      Applying admin.0003_logentry_add_action_flag_choices... OK
      Applying contenttypes.0002_remove_content_type_name... OK
      Applying auth.0002_alter_permission_name_max_length... OK
      Applying auth.0003_alter_user_email_max_length... OK
      Applying auth.0004_alter_user_username_opts... OK
      Applying auth.0005_alter_user_last_login_null... OK
      Applying auth.0006_require_contenttypes_0002... OK
      Applying auth.0007_alter_validators_add_error_messages... OK
      Applying auth.0008_alter_user_username_max_length... OK
      Applying auth.0009_alter_user_last_name_max_length... OK
      Applying sessions.0001_initial... OK

Next, your would create an admin account. You’re done.

Written by maclochlainn

September 10th, 2019 at 12:47 pm

PostgreSQL on Fedora 30

with one comment

Installing PostreSQL 11 on Fedora 30 wasn’t straight forward but there were some instructions that helped. The first step requires you to update the yum repository, like this as the root user:

rpm -Uvh https://yum.postgresql.org/11/fedora/fedora-30-x86_64/pgdg-fedora-repo-latest.noarch.rpm

Then, you install the PostgreSQL with this command as the root user:

dnf install postgresql11-server

After installing the PostreSQL Server I got a few errors with the symbolic links failing to resolve in the log files. Then, I realized they only failed to create symbolic links because the fresh installation deploys executables directly to the /usr/bin directory.

After installing the PostgreSQL Server 11, you need to initialize the database. You use the following command to initialize the database as the root user:

/usr/pgsql-11/bin/postgresql-11-setup initdb

It should return the following:

Initializing database ... OK

The PostgreSQL Server 11 database installs in the /var/lib/pgsql/11/data directory. You can list the contents, which should mirror these:

drwx------. 5 postgres postgres  4096 Aug 19 02:45 base
drwx------. 2 postgres postgres  4096 Aug 19 02:45 global
drwx------. 2 postgres postgres  4096 Aug 19 02:45 log
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_commit_ts
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_dynshmem
-rw-------. 1 postgres postgres  4269 Aug 19 02:45 pg_hba.conf
-rw-------. 1 postgres postgres  1636 Aug 19 02:45 pg_ident.conf
drwx------. 4 postgres postgres  4096 Aug 19 02:45 pg_logical
drwx------. 4 postgres postgres  4096 Aug 19 02:45 pg_multixact
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_notify
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_replslot
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_serial
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_snapshots
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_stat
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_stat_tmp
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_subtrans
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_tblspc
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_twophase
-rw-------. 1 postgres postgres     3 Aug 19 02:45 PG_VERSION
drwx------. 3 postgres postgres  4096 Aug 19 02:45 pg_wal
drwx------. 2 postgres postgres  4096 Aug 19 02:45 pg_xact
-rw-------. 1 postgres postgres    88 Aug 19 02:45 postgresql.auto.conf
-rw-------. 1 postgres postgres 23895 Aug 19 02:45 postgresql.conf

You need to enable and start the postgresql-11.service with the following commands as the root user:

systemctl enable postgresql-11.service
systemctl start postgresql-11.service

You can login to test the configuration as the root user, like this:

su - postgres -c "psql"

You will see something like this:

psql: /usr/pgsql-11/lib/libpq.so.5: no version information available (required by psql)
psql: /usr/pgsql-11/lib/libpq.so.5: no version information available (required by psql)
psql (11.4, server 11.5)
Type "help" for help.
 
postgres=#

The error message appear to indicate there’s a bug (at least Bug #15798 is similar). Specifically, a missing function in the libya.so.5 library. Determining that impact took some time because of what else I had in the queue.

The Bug (at least Bug #15798 gave part of the fix. The problem was figuring out where the LD_LIBRARY_PATH should really be set, and I sorted that out.

If you inspect the postgres home directory (/var/lib/pgsql), you’ll find the following .bash_profile file:

[ -f /etc/profile ] && source /etc/profile
PGDATA=/var/lib/pgsql/11/data
export PGDATA
# If you want to customize your settings,
# Use the file below. This is not overridden
# by the RPMS.
[ -f /var/lib/pgsql/.pgsql_profile ] && source /var/lib/pgsql/.pgsql_profile

Then, you create the .pgsql_profile file in that directory. You should put the following command in the file:

export set LD_LIBRARY_PATH=/usr/lib64 needle < /dev/null

Then, when you login as the postgres user:

psql -U postgres

You will see:

psql (11.4, server 11.5)
Type "help" for help.
 
postgres=#

or, you can login to test the configuration as the root user with the syntax used earlier:

su - postgres -c "psql"

You need to put the LD_LIBRARY_PATH environment variable in the .bashrc of users who will access the PostgreSQL 11 database.

As always, I hope this helps those working it from the ground up.

Written by maclochlainn

August 19th, 2019 at 3:06 am

Apache on Fedora 30

with one comment

There was an option during the Fedora 30 Workstation installation to add the Apache Web Server, but you need to set it to start automatically. Unfortunately, there was no option to install PHP, which I thought odd because of how many web developers learn the trade first on PHP with a LAMP (Linux, Apache, MySQL, Perl/PHP/Python) stack. You see how to fix that shortcoming in this post and how to install and test PHP, mysqli, and pdo to support MySQL 8.

Before you do that make sure you install MySQL 8. You can find my prior blog post on that here.

You set Apache to start automatically, on the next boot of the operating system, with the following command:

chkconfig httpd on

It creates a symbolic link:

Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.

However, that command only starts the Apache server the next time you boot the server. You use the following command as the root user to start the Apache server:

apachectl start

You can verify the installation with the following command as the root user:

ps -ef | grep httpd | grep -v grep

It should return:

root      5433     1  0 17:03 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5434  5433  0 17:03 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5435  5433  0 17:03 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5436  5433  0 17:03 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5437  5433  0 17:03 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5438  5433  0 17:03 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache    5442  5433  0 17:03 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND

and, then verify the listening port with the following command as the root user:

netstat -tulpn | grep :80

It should return the following when both the Apache server is listening on port 80 and the Oracle multi-protocol server is listening on port 8080:

tcp6       0      0 :::80                   :::*                    LISTEN      119810/httpd        
tcp6       0      0 :::8080                 :::*                    LISTEN      1403/tnslsnr

You can also enter the following URL in the browser to see the Apache Test Page:

http://localhost

It should display the test page, like this:

You can also create a hello.htm file in the /var/www/html directory to test the ability to read an HTML file. I would suggest the traditional hello.htm file:

<html>
<body>
Hello World!
</body>
</html>

You can call it by using this URL in the browser:

http://localhost/hello.htm

It should display the test page, like this:

Now, let’s install PHP. You use the following command as a privileged user, which is one found in the sudoer’s list:

yum install -y php

Before you test the installation of PHP in a browser, you must restart the Apache HTTP Server. You can do that with the following command as a privileged user:

sudo apachectl restart

After verifying the connection, you can test it by creating the traditional info.php program file in the /var/www/http directory. The file should contain the following:

1
2
3
<?php
  phpinfo();
?>

It should display the PHP Version 7.3.8 web page, which ships with Fedora 30:

The next step shows you how to install mysqli and pdo with the yum utility. While it’s unnecessary to check for the older mysql library (truly deprecated), its good practice to know how to check for a conflicting library before installing a new one. Also, I’d prefer newbies get exposed to using the yum utility’s shell environment.

You start the yum shell, as follows:

yum shell

With the yum shell, you would remove a mysql package with the following command:

> remove php-mysql

The command will remove the package or tell you that there is no package to remove. Next, you install the php-mysqli package with this command:

install php-mysqli

You will then be prompted to confirm the installation of the php-mysqli library. Finally, you exit the yum shell with this command:

> quit

If you want to see the whole interactive shell, click on the link below.

You need to restart the Apache HTTP listener for these changes to take place, which you do with the same command as shown earlier:

sudo apachectl restart

I wrote the mysqli_check.php script to verify installation of both the mysqli and pdo libraries. The full code should be put in a mysqli_check.php file in the /var/www/html directory for testing.

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
<html>
<header>
<title>Static Query Object Sample</title>
<style type="text/css">
  /* HTML element styles. */
  table {background:white;border-style:solid;border-width:3px;border-color:black;border-collapse:collapse;}
  th {text-align:center;font-style:bold;background:lightgray;border:solid 1px gray;}
  td {border:solid 1px gray;}
 
  /* Class tag element styles. */
  .ID {min-width:50px;text-align:right;}
  .Label {min-width:200px;text-align:left;}
</style>
</header>
<body>
<?php
  if (!function_exists('mysqli_init') && !extension_loaded('mysqli')) {
    print 'mysqli not installed.'; }
  else {
    print 'mysqli installed.'; }
  if (!function_exists('pdo_init') && !extension_loaded('pdo')) {
    print '<p>pdo not installed.</p>'; }
  else {
    print '<p>pdo installed.</p>'; }
?>
</script>
</body>
</html>

You can test it with the following URL from the local browser:

http://localhost/mysqli_check.php

It should print the following to the web page when you’ve successfully install the mysqli and pdo libraries:

mysqli installed.
pdo installed.

If you plan to use PHP to display and render graphics, you need to install php-gd library. You can do that with the yum utility and this prior blog post explains it. Don’t forget to restart the Apache HTTP Server after you add the php-gd library.

For example, one of my sample PHP programs loads a PNG image into a BLOB column as raw binary text. Then, the program reads it and renders it with PHP to produce the following web page.

As always, I hope this helps those looking for a complete solution without cost.

Written by maclochlainn

August 16th, 2019 at 12:26 pm

Linux mongod Service

with one comment

The installation of MongoDB doesn’t do everything for you. In fact, the first time you start the mongod service, like this as the root user or sudoer user with the command:

service mongod start

A sudoer user will be prompted for their password, like

A typical MongoDB instance raises the following errors:

Redirecting to /bin/systemctl start mongod.service
[student@localhost cit425]$ mongo
MongoDB shell version v3.4.11
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.11
Server has startup warnings: 
2018-10-29T10:51:57.515-0600 I STORAGE  [initandlisten] 
2018-10-29T10:51:57.515-0600 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2018-10-29T10:51:57.515-0600 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2018-10-29T10:51:58.264-0600 I CONTROL  [initandlisten] 
2018-10-29T10:51:58.264-0600 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.                                                                                               
2018-10-29T10:51:58.264-0600 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.                                                                              
2018-10-29T10:51:58.264-0600 I CONTROL  [initandlisten]                                                  
2018-10-29T10:51:58.265-0600 I CONTROL  [initandlisten]                                                  
2018-10-29T10:51:58.265-0600 I CONTROL  [initandlisten] ** WARNING: soft rlimits too low. rlimits set to 15580 processes, 64000 files. Number of processes should be at least 32000 : 0.5 times number of files.

You can fix this by following the MongoDB instructions for the Unix ulimit Settings, which will tell you to create a mongod file in the /etc/systemd/system directory. You should create this file as the root superuser. This is what you should put in the file:

[Unit]
Description=MongoDB
Documentation=man:mongo
 
[Service]
# Other directives omitted
# (file size)
LimitFSIZE=infinity
# (cpu time)
LimitCPU=infinity
# (virtual memory size)
LimitAS=infinity
# (locked-in-memory size)
LimitMEMLOCK=infinity
# (open files)
LimitNOFILE=64000
# (processes/threads)
LimitNPROC=64000

Then, you should be able to restart the mongod service without any warnings with this command:

service mongod restart

As always, I hope this helps somebody.

Written by maclochlainn

October 29th, 2018 at 11:39 am

MySQL 5.7.* and mysqli

without comments

After installing MySQL 5.7.22 and PHP 7.1.17 on Fedora 27, you need to install the mysqli library. You need to verify if the mysqli library is installed. You can do that with the following mysqli_check.php program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<html>
<header>
<title>Check mysqli Install</title>
</header>
<body>
<?php
  if (!function_exists('mysqli_init') && !extension_loaded('mysqli')) {
    print 'mysqli not installed.'; }
  else {
    print 'mysqli installed.'; }
?>
</script>
</body>
</html>

You test preceding PHP program with the following URL in a browser:

http://localhost/mysqli_check.php

If the mysqli program isn’t installed, you can install it as follows by opening the yum interactive shell:

[root@localhost html]# yum shell
Last metadata expiration check: 1:26:46 ago on Wed 22 Aug 2018 08:05:50 PM MDT.
> remove php-mysql
No match for argument: php-mysql
Error: No packages marked for removal.
> install php-mysqlnd
> run
================================================================================================
 Package                 Arch               Version                   Repository           Size
================================================================================================
Installing:
 php-mysqlnd             x86_64             7.1.20-1.fc27             updates             246 k
Upgrading:
 php                     x86_64             7.1.20-1.fc27             updates             2.8 M
 php-cli                 x86_64             7.1.20-1.fc27             updates             4.2 M
 php-common              x86_64             7.1.20-1.fc27             updates             1.0 M
 php-fpm                 x86_64             7.1.20-1.fc27             updates             1.5 M
 php-json                x86_64             7.1.20-1.fc27             updates              73 k
 php-pdo                 x86_64             7.1.20-1.fc27             updates             138 k
 php-pgsql               x86_64             7.1.20-1.fc27             updates             135 k
 
Transaction Summary
================================================================================================
Install  1 Package
Upgrade  7 Packages
 
Total download size: 10 M
Is this ok [y/N]: y

After you type y and the return key, you should see a detailed log of the installation. Click the link below to see the yum installation log detail.

After you install the mysqli library, you exit the yum interactive shell with the quit command as shown:

> quit
Leaving Shell
The downloaded packages were saved in cache until the next successful transaction.
You can remove cached packages by executing 'dnf clean packages'.

You can now retest by re-running the mysqli_check.php program with the following URL:

http://localhost/mysqli_check.php

Image processing is not generally installed by default. You should use the following yum command to install the PHP Image processing library:

yum install -y php-gd

Or, you can use dnf (Dandified yum), like:

dnf install -y php-gd

Click the link below to see the yum installation log detail.

If you encounter an error trying to render an image like this:

Call to undefined function imagecreatefromstring() in ...

The php-gd package is not enabled. You can verify the contents of the php-gd package with the following rpm command on Fedora or CentOS:

rpm -ql php-gd

On PHP 7.1, it should return:

/etc/php-zts.d/20-gd.ini
/etc/php.d/20-gd.ini
/usr/lib/.build-id
/usr/lib/.build-id/50
/usr/lib/.build-id/50/11f0ec947836c6b0d325084841c05255197131
/usr/lib/.build-id/b0/10bf6f48ca6c0710dcc5777c07059b2acece77
/usr/lib64/php-zts/modules/gd.so
/usr/lib64/php/modules/gd.so

Then, you might choose to follow some obsolete note from ten or more years ago to include gd.so in your /etc/php.ini file. That’s not necessary.

The most common reason for incurring this error is tied to migrating old PHP 5 code forward. Sometimes folks used logic like the following to print a Portable Network Graphics (png) file stored natively in a MySQL BLOB column:

  header('Content-Type: image/x-png');
  imagepng(imagecreatefromstring($image));

If it was stored as a Portable Network Graphics (png) file, all you needed was:

  header('Content-Type: image/x-png');
  print $image;

As always, I hope this helps those looking for a solution.

Written by maclochlainn

August 23rd, 2018 at 11:47 am