CodeIgniter 4: Build a Complete Web Apps from Scratch

Codeigniter is a popular PHP-based web application platform for building high-quality web apps, websites, content management systems, and e-commerce stores.

Web development has progressed significantly as a result of the widespread use of mobile devices and the digitization of industries, and specific solution-based application development has become a requirement of the hour. Developing multi-device supporting solutions that are reliable, scalable, and stable has become the most in-demand service in today’s world.

PHP is an open-source scripting language among developers because of its ease of use. To put it another way, the PHP framework supports the creation of a simple platform for companies and entrepreneurs to build seamless web applications. This framework enables developers to use pre-built modules rather than writing repetitive code, saving time and allowing for a shorter development cycle, resulting in faster app development.

Best-in-class coding practices and development procedures are included in the PHP framework, which aids in the coordination and protection of the process. 

CodeIgniter and its various aspects

CodeIgniter is a website-building framework based on the PHP programming language. It’s a completely free framework to use. It features several advantages such as easy to upload and operate your website.

Codeigniter is a perfect solution for those who want to build projects from scratch without the need of installing any other software on their machine.

If you know PHP, CodeIgniter will facilitate your work. It comes with a multitude of libraries and assistants. If you build a site from the ground up, CodeIgniter will save you a lot of time. Furthermore, a CodeIgniter website development is safe, as it can prevent a variety of website-based attacks.

CodeIgniter is a lightweight PHP framework for developers who want to develop complete, simple, elegant Web applications. CodeIgniter is a technology institutional document developed by EllisLab and is a British Columbia Institute project.

A developer may choose to master one or more of the frameworks mentioned above, but the one that is the most current in terms of market dynamics and demand should be prioritized over the others. See the benefits and disadvantages of using CodeIgniter website development.

CodeIgniter 4.1.5 is the latest version of the framework, intended for use with PHP 7.3+ (including 8.0). Last updated on Nov 08, 2021.

codeigniter.com

Advantages of CodeIgniter website development

CodeIgniter is a PHP MVC framework that allows developers to quickly create full-featured dynamic applications. The MVC (Model-View-Controller) architecture of CodeIgniter helps create multiple processes of the development cycle simultaneously with successful design, with a variety of libraries and packages enabling linking databases to perform diverse operations such as file uploads, session management, email sending, and more.

MVC Architecture

The MVC (Model-View-Controller) framework is used by CodeIgniter to create website designs. MVC is an architecture or design model used in the development of websites. The design structure is divided into three parts, as the name suggests, allowing for easy customization.

  • Model – The model, which is in charge of data management, establishes the base layer.
  • View – The data would be then forwarded to the receiver.
  • Controller – The controller’s role is to keep all of the previous levels’ links on the same page.

Form Validations

The form validation feature is critical in web application development. It allows you to capture and file data in the appropriate format. It also makes the job of developers much easier and more enjoyable. The CodeIgniter system makes custom validation easy, and it comes with a number of built-in type validations, making it unsuitable for scripts.

Inbuilt Security Tools

In PHP CodeIgniter website development facilities, excluding slashes when recovering data from the database is a common practice. Due to built-in security tools, these patches are interpreted in default settings. When feeding to a query, these default settings fix the database problem by disabling the runtime guidelines for magic quotes. Thanks to these useful features, the CodeIgniter website development process is quick and easy for developers.

Error Handling

During the CodeIgniter website development process, developers who use the CodeIgniter web application development framework may find it easier to access error reports. The framework also supports the saving of debugging messages as text files with error logging class instructions. This feature is extremely useful for programmers.

Database Caching Class

The following easy steps can be found for the cache. Reduce loading by storing text file queries.

  • Build a writeable directory on the server that stores and saves cache files
  • Set the path to the cache folder in the application/config/database.php file
  • You can turn on the caching function globally or manually in the application/config/databank.php file.

Since CodeIgniter has a simple integration feature, cutting-edge web applications developed with it can help businesses all over the world, making it the most preferred web platform for developers.

PSR Compliance

The PHP-FIG was created in 2009 to help make code more interoperable between frameworks by ratifying Interfaces, style guides, and more that members were free to implement or not. While CodeIgniter is not a member of the FIG, we are compatible with a number of their proposals. This guide is meant to list the status of our compliance with the various accepted, and some draft, proposals.

Server Requirements

PHP version 7.3 or newer is required, with the *intl* extension and *mbstring* extension installed.

How to find a skilled team to outsource Codeigniter development?

Codeigniter is a popular open-source PHP web application framework. It’s a powerful and flexible tool for experienced programmers, but it’s also a great option for beginners.

In this section there are some tips on how to find codeigniter developers:

You should look into their online portfolio and check the quality of their projects as well as the number of projects that they have done in the past. You can also ask them about what type of freelance jobs they prefer, or if they prefer working with one company or multiple clients at once.

Conclusion

Codeigniter framework is a popular PHP-based web application platform for building high-quality web apps, websites, content management systems, and e-commerce stores. The framework combines a highly immersive interface with a collection of simple tools to make it ideal for developers. Codeigniter is a common option due to additional features such as simplicity, versatility, and security. If you want to have a smart and vibrating web application, you should use CodeIgniter website development

PHP vs ASP.NET: Which is Better for Web Development?

There is a growing trend toward progressive web applications that empower users and enhance interoperability as well as facilitate the development process. Market demands are growing extremely fast, and it is obvious that the right technology stack can make the difference for a project.

According to statistics, two programming languages – PHP and ASP.NET – occupy the most part of the server technology market, so the question arises – which one is better for web development. Let’s learn more about each approach, its pros and cons, main differences and why it can work better in certain cases.

ASP.NET and Web Development

ASP.NET is a C# based web application server platform. It was introduced by Microsoft in the early 2000s as an extension of the .NET platform. This framework offers many libraries and tools, especially for web development. Moreover, any other packages available on the .NET platform, such as Visual Studio, can comfortably be used by web developers.

Microsoft provides a basic structure for handling requests along with a web page template syntax, authentication system, editor extensions, and template libraries. This framework allows you to develop different types of applications, including dynamic web pages, microservices, REST APIs and real-time hubs. The Microsoft team is constantly improving functionality and introduces a huge ecosystem of open source libraries. However, it is an open source platform supported by Microsoft, developers are also encouraged to contribute to the community.

Among the major features is a web page template syntax called Razor. This allows developers to write internal code in C#. Once the code is evaluated on the server, the HTML content will be sent to users. In addition, the user side is written in JavaScript, which integrates effectively with ASP.NET. Various editor extensions allow you to augment the code and highlight syntax.

Previously, ASP.NET web applications ran only on Microsoft servers, which typically required higher hosting fees. With the new 2016 version of ASP.NET Core, software developers can apply for Linux and macOS hosting services. In light of the relationship between ASP.NET and web development, we can conclude that this framework provides a reasonable solution and has a number of advantages to choose from for your next project.

IS ASP.NET SUITABLE FOR WEB DEVELOPMENT

In fact, any web technology can be a great choice for a project, as long as it meets the set expectations. Having given a comprehensive answer to the question “why use ASP.NET for web development?”, We would like to identify the most important aspects to consider.

To begin with, ASP.NET is a mature platform that has been on the market for more than a few decades. Compared to other frameworks, it has gained a decent market share and continues to strengthen them through continuous development. Today’s community consists of more than 60,000 developers from around the world. As an open-source platform, it is also actively supported by Microsoft and is known for active community support. This close cooperation leads to the availability of various libraries and clear guidelines. Microsoft invests heavily in developing its platforms and supporting the community. There is no fear that they will offer some outdated approaches.

On the technology side, ASP.NET is often chosen because it is fast and efficient. You only need to compile once because the .NET platform is capable of running compiled code over and over again. Unlike interpreted code that must be executed every time on a machine, compiled code is more consistent and scalable.

Scalability is a great performance gas pedal. It covers code optimization as well as architecture and infrastructure, including intercepts, networking, etc. D. This framework provides vertical scalability, which aims to reduce overall delivery time.

One of the distinct advantages is robust security. This web application framework supports all necessary authentication protocols. ASP.NET offers a number of built-in features for overall application security, as well as cross-site scripting and request forgery. In addition to multi-factor authentication, the framework provides it externally, such as with Google.

Previously, developers had to buy an IDE to write code. Nowadays, free tools and libraries are available to everyone. However, often professional development companies pay for additional licenses to get more functionality. Moreover, all web-based software requires hosting servers. Windows hosting is more expensive compared to Linux servers. In addition, there is Microsoft IIS, which is available for free for different versions of Microsoft Windows.

As a result, ASP.NET web development services have become a great solution for many companies due to their excellent functionality, security and regular improvements.

PHP Web Development

PHP as a web development server language evolved from a small open-source project. It was created in 1995 by Rasmus Lerdorf, who wrote several CGI programs and managed to make them work with web forms and databases. He didn’t aim to create a new programming language, but it has evolved into one of the largest open-source languages. Anyone can contribute to the new release, including task deployment, testing, documentation, and source code.

Because of its accessibility, PHP has gained popularity among a huge number of developers. It can be a common choice for beginners because its learning curve is much simpler compared to others.

The PHP community has various free open-source libraries, tools and extensions. For example, the MySQL extension, it allows developers to build PHP applications that interact with the database, providing improved support for statements and transactions.

In light of the ASP vs. PHP comparison, PHP developers are dealing with a different type of code – interpreted code, which is written entirely in C. It allows excellent customization, however, which can be the cause of some errors and poor coding.

Because this server-side language was originally released for web development, it is effective for interoperability and access to most types of databases. Because of its adaptability and flexibility, developers are not limited in their choices. Furthermore, PHP can support other services covering various protocols, such as POP3, HTTP, IMAP, LDAP, etc.

Pros and Cons for PHP

Pros:

  • It is open-source and free for users.
  • It has a vast community of dedicated developers worldwide.
  • PHP is the best choice for large projects like Facebook.
  • It is also a perfect choice for web-based scripts such as web content management systems (CMS) due to efficient communication with various database types.
  • You can customize it for your needіs, and it is highly scalable.
  • It is cost-efficient and easy to learn, code, and pick up.

Cons:

  • PHP is generally not suitable for desktop applications, as it targets web applications.
  • PHP applications tend to run slower than apps built with other programming languages.
  • Customization options can lead to bugs and poor coding.
  • In comparison with other programming languages, PHP lacks efficiency in error handling. Therefore, it takes more time to detect errors.

Consequently, open-source turned out to be a great solution for the PHP web development community. They have gained the largest market share and continue to make continuous improvements and regular releases.

WHY WE USE PHP FOR WEB DEVELOPMENT

While this may seem like an easy question to answer, we wanted to be more specific and identify the pros and cons of this approach to development.

The first reason we use PHP for web development is that this programming language was originally introduced as a web scripting language. It is strongly supported and improved by its own community of more than 5 million PHP developers. The open-source programming language is quite popular among newcomers and has gained the largest market share. Its supporting community has continued to grow for more than 25 years.

Working with open source has its advantages and disadvantages. In fact, this language is easy to learn, it is compatible with different servers and suitable for various web applications. Another difference of PHP development is the interpreted code. This type of code is usually executed on the server, later generated in HTML and only then sent to the user side. Accordingly, the execution time is longer and an error may occur when importing heavy files, resulting in lower performance compared to other languages.

On the other hand, web development in PHP is often chosen to increase scalability. This is achieved by adding additional servers. The total workload will be distributed among them and will be able to handle more user requests. This approach is based on horizontal scalability, which distinguishes PHP from ASP.NET.

With a number of built-in security features, PHP is still considered less secure than other web server programming languages. By gaining more flexibility when writing code, engineers have more responsibility for its security and cannot rely solely on tools built into the build.

Reduced development and maintenance costs are usually considered a big advantage. PHP developers have access to all tools and libraries without any additional fees. Moreover, developers can choose between different hosting services and be able to pay less.

This adaptable and flexible programming language can easily meet basic web development needs. However, companies need to first outline their needs and make sure that they meet the established requirements and end goals.

ASP.NET vs. PHP: the Best Framework for Web Development

Any company starting a web development project may face this common question – ASP.NET vs. PHP: which is better. Undoubtedly, each approach has its own advantages. Moreover, they have worked effectively on different projects, and companies are really happy with the end results.

The thing is, companies need to approach the choice of ASP.NET and PHP from a different perspective – which is better for their project, which points are of most concern. It is possible to follow a simple advice – all requirements should be divided into business and technology aspects. Obviously, it makes no sense to choose some technology that has a large market share, but does not meet any of your technical requirements.

Let’s look at some important factors in light of the business aspects of ASP.NET and PHP.

ASP.NET vs. PHP: the business side

Both technologies have been on the market for a long time and have gained special recognition among web developers. Because PHP was released earlier and was originally introduced as a web programming language, its community has grown faster than the ASP.NET community. There is now a high market demand for these developers, as SPA and SaaS applications are the new default business standard.

In terms of support, developers are offered very different approaches. As mentioned above, although ASP.NET is also open source, it is supported by Microsoft, while PHP is an open source project. Community support is always great, but some complex projects may require professional help and immediate solutions.

Among the users of these web-based approaches you can find many well-known companies. For example, UPS, Stack Overflow, DELL use ASP.NET, while Facebook, WordPress and Wikipedia practice web development in PHP.

The final choice between ASP.NET and PHP mainly depends on the technologies that affect the overall functionality of the application. More research is needed to understand which options to implement the idea are most acceptable.ASP.NET vs. PHPPerformance is a key requirement for any project. Everyone wants to provide their users with a fast and efficient solution. ASP.NET will be the clear winner here because the compiled code is more accurate and systematic.

In addition to different coding methods, enterprises should pay particular attention to scalability, which greatly improves service performance. Vertical scalability focuses on getting more capacity (CPU, RAM) for existing machines, while horizontal scalability focuses on adding more machines.

As far as comparing ASP.NET and PHP, we have to mention security as one of the main requirements. It is worth the effort to get software with a high degree of security. Of course, this can also depend on the project. When the business is dealing with tons of data, it is better to use ASP.NET. But if it’s an open-source small project, PHP would be a great addition.

PHP is an open-source programming language that requires no paid tools or licenses. However, the extra cost spent on ASP.NET development definitely pays off through improved functionality and high quality.

Consequently, there is no clear answer to the question raised between ASP.NET and PHP. The final choice is always determined according to the company’s stated requirements and available resources.

CONCLUSION

We have collected the most important details, which usually affect the choice of web development strategy. The main thing to remember is that each method has significant advantages. Always take a moment to outline the needs of your project. Choosing between ASP.NET and PHP will be easier if the company sets certain requirements and finds reasonable ways to meet them. Another great solution is to consult with some professionals who have web development experience.

TOP 9 best PHP IDEs for Web Developers in 2021

IDE is a software application that provides comprehensive facilities to computer programmers for software development.

There are a lot of IDEs accessible in the market, both for Free and Paid, and picking one can be a tricky job.

Integrated Development Environment Definition:

An integrated development environment (IDE) is a software application that provides comprehensive facilities to computer programmers for software development. An IDE normally consists of a source code editor, build automation tools, and a debugger. Most modern IDEs have intelligent code completion. Wikipedia link

What does IDE stand for software?

Here the Best 9 IDEs for Developing on PHP we will be looking at:

 

PhpStorm is perfect for working with Symfony, Drupal, WordPress, Zend Framework, Laravel, Magento, Joomla!, CakePHP, Yii, and other frameworks.

The editor actually ‘gets’ your code and deeply understands its structure, supporting all PHP language features for modern and legacy projects. It provides the best code completion, refactorings, on-the-fly error prevention, and more.

2. Cloud 9

Also See: Community big PHP IDEs list

 

3. Komodo IDE

With discounts for students, freelancers, and individuals for $147

 

4. Koding

Open-Source and Education FREE, Solo Developers $1/mo.

 

5. Eclipse

You can easily combine language support and other features into any of our default packages, and the Eclipse Marketplace allows for virtually unlimited customization and extension.

Load PHP IDE by Eclipse.

 

6. Sublime Text

 

7. Atom

8. Brackets

9. Netbeans

  • Platform(s): Microsoft Windows, Mac OS X, Linux, Solaris
  • Supported Languages: Java ME & SE, JavaScript, HTML5, PHP, C/C++, XML, Groovy, Javadoc, JSP
  • Price: FREE (CDDL or GPLv2)
  • More Information: Integration of Subversion, Mercurial, and Git, NetBeans Profiler
 

Best lightweight IDE for PHP programming?


So, if you are a PHP Programmer or even a beginner — save this page!

Sources:

How to Use PHP to Send Web Push Notifications for Your Web Site

Many sites need to keep their users up to date about new content even when they are not looking at the site.

Web push notifications can solve this problem by showing notification windows with short messages telling the user there is something new on the site that they authorized to be notified when new content is publishe.

Read this tutorial article to learn about how you can implement Web push notifications in your sites using PHP.

In this article you can read about the following:

  1. Overview
    • A brief view on web push notifications
    • How web push notifications works
      • The subscription process
      • Sending notifications
      • The required key pair (VAPID)
  2. Implementation
    • The subscription on the client side
      • Check whether push notifications are available
      • Obtain permission to deliver push notifications to the user
      • Registration of the service-worker
      • Implementation of the service-worker
    • Receive and save subscriptions on the server
    • Create and send notifications
      • The header
      • Encrypt the payload
      • Send the notification via HTTP-request
  3. Appendix
    • How long is a Subscription valid?
    • Standardbrowser settings to display notifications
    • Debugging and testing the service-workers

1. Overview

To implement web push notifications on your site page, appropriate functionality must be provided both on the user client side and on the server.

The user client must first subscribe to the notifications and then receive and display them. On the client side, JavaScript is used for this. The standard web push API is implemented in almost all popular desktop and mobile browsers.

Subscriptions must be saved and managed on the server side and the desired messages sent. In this tutorial, the server side is implemented with PHP, since this is the most used platform and therefore this could be the easiest way to integrate into an existing system.

Packets found on the Internet all have multiple dependencies on other packets (signing, encryption, asynchronous sending of HTTP requests) and therefore also a very high overhead of unused ballast. For this reason, I decided to create a package based on the available sources that has no further external dependencies.

The complete source code of the steps described below and the PHP package for sending push notifications can be found here (PNServer).

1.1. A brief view on web push notifications

Web push notifications allow messages to be sent directly to users, even if they are not currently visiting the sender’s site page.

Offers, news or other relevant information can be sent at any time and users can be redirected to a desired URL. From the user’s point of view, push notifications have the advantage that the entire subscription process is anonymous (the provider does not need names or contact details such as an email address or other information) and the service can be terminated at any time.

In order for a provider to be allowed to send push notifications to a user, the user must first explicitly take any action on the sender’s web site to confirm that he wants to receive these messages.

In addition, a unsubscribe option is automatically integrated in each delivered push message (how and where this unsubscribe option is offered depends on the users operating system and/or browser).

The push notifications are not displayed within the web site area of a browser, but either in a separate popup window or via a service provided by the operating system (this varies depending on the device, operating system and browser and some browsers allow marginally settings – see also in the appendix).

A notification usually consists of a title, a short text (optionally with an icon and/or a picture) and usually contains a direct link to the web site it relates to.

The notification system is an extremely powerful medium for interacting with users. However, the provider should always take care not to publish too much on this medium, otherwise users will deactivate all notifications.

1.2. How web push notifications works

An external push service is connected between the browser at client side and the message provider’s server. The push service is responsible for delivering messages from the server to the respective users.

When requesting information about the subscription from the web push API, the public part of a key must be passed. With the help of the private part of this key, the server in turn has to encrypt the messages before sending them.

1.2.1. The subscription process

Code for two tasks must be integrated on your site page. The first is to give the visitor the opportunity to subscribe to the web push notifications. In addition, the site page must install a service (‘service-worker’), with which the client is registered on the server and received messages are processed. The service-worker is downloaded in the background to the client platform so that it can be executed outside of the context of the site page.

If the user subscribes to the service, the service-worker is registered (1). The service-worker in turn requests all required information through the web push API (2) and sends this via an HTTP request (3) to the server. The server stores this information in his database (4) so that notifications can be sent to the client.

1.2.2. Sending notifications

Notifications can now be sent from the server to all registered subscriptions with a HTTP request (2). In order to correctly identify yourself, a signature must be transmitted in the request header. This signature is generated from the public key used for registration together with the private part of the key (1). The actual message and possibly further information are transmitted as user data – also encrypted. If the formatting and encryption are correct and the signature validated, the push service sends the notification to the client (3).

1.2.3. The required key pair (VAPID)

A key pair containing a public and a private key is required for the whole process. These two keys are called VAPID keys (VAPID: Voluntary Application Server Identification for Web Push; RFC 8292 – https://tools.ietf.org/html/rfc8292) and have to be generated once for a web site.

There are various tools available for creating a VAPID key pair. Alternatively, online a key pair can be generated e.g. at https://tools.reactpwa.com/vapid. The private key should never be visible to the end user (e.g. in a JS script or somewhere else), but should only be used on the server for encryption when creating notifications. VAPID protection ensures that notifications can only be sent to clients from the authorized server.

Very detailed information about VAPID can be found in the following blog post:
https://blog.mozilla.org/services/2016/04/04/using-vapid-with-webpush/

2. Implementation

After the general consideration in the previous chapter, we now turn to the actual programming.

2.1. The subscription on the client side

Since the client side runs in the web browser, everything on the client is implemented in JavaScript. Note that the integration of the functions within the UI of the web site is not part of this tutorial!

Some functions in connection with the web push API are processed asynchronously, which is why the promise pattern is used several times in the following code. Numerous articles on this topic can be found on the internet – at https://web.dev/promises/ beginners can find a very good explanation.

2.1.1. Check whether push notifications are available

First of all, it must be checked whether all requirements are met in order to be able to receive push notifications on the current browser. To do this, the browser must support the web push API and the Web site must run in a secure context (HTTPS).

For more info about the API and the availability in the current browsers see https://www.w3.org/TR/push-api/ and https://caniuse.com/#feat=push-api.function pnAvailable() {
var bAvailable = false;
if (window.isSecureContext) {
// running in secure context – check for available Push-API
bAvailable = ((‘serviceWorker’ in navigator) &&
(‘PushManager’ in window) &&
(‘Notification’ in window));
} else {
console.log(‘site have to run in secure context!’);
}
return bAvailable;
}

2.1.2. Obtain permission to deliver push notifications to the user

Due to the misuse of push notifications in the past, consent to display notifications should only be requested after the user has deliberately acted on it (e.g. by clicking a button – not automatically when the page loads!).

The following function should therefore best be integrated on your own Web site using a link or button in a separate area with corresponding explanations for the push notifications. This should be seen as a rule and not just as ‘best practice’.

As a provider, it should be borne in mind that many (… most) users are more likely to reject an early request without detailed explanations. And once the request has been rejected, it is difficult to get the user back on board later.

If the user has already rejected the display of notifications, he should no longer be bothered with further information regarding the subscription to the push notifications, since he must first deactivate the blocking of the notifications via the respective browser function! If necessary, this can be explained in more detail at a suitable point (e.g. under FAQ’s).async function pnSubscribe() { if (pnAvailable()) { // if not granted or denied so far… if (window.Notification.permission === ‘default’) { await window.Notification.requestPermission(); } if (Notification.permission === ‘granted’) { // register service worker await pnRegisterSW(); } } }

The browser remembers the user’s last selection. This can be determined at any time via the notification.permission property. If the user has not yet made a decision, this property is set to ‘default’, otherwise to ‘denied’ or ‘granted’. With most browsers, the decision can be reset by the user in the title bar or in the page settings.

2.1.3. Registration of the service-worker

In order to receive and display push notifications, even if the user is not on that site page, a service must be registered running in the background outside the context of the website and is therefore always ready to respond to notifications.

The so called service-worker is a separate javascript file that the browser copies from the origin location on the web to the local computer and executed there.async function pnRegisterSW() { navigator.serviceWorker.register(‘PNServiceWorker.js’) .then((swReg) => { // registration worked console.log(‘Registration succeeded. Scope is ‘ + swReg.scope); }).catch((e) => { // registration failed console.log(‘Registration failed with ‘ + e); }); }

It is not necessary to check whether the service-worker has already been registered. The browser (… the web push API) takes care of it. After registration, everything within the context of the website is done. All further steps are carried out within the service-worker.

All required functions and some helpers while testing included in PNClient.js.

2.1.4. Implementation of the service-worker

In the context of our site page, we have registered the service-worker so far and are now dedicated to his tasks. When registering, the specified javascript file was downloaded and executed. The registration succeeds only if the script could be executed without errors.

The only code in the service worker that is executed directly is to register listeners for several events:// add event listener to subscribe and send subscription to server self.addEventListener(‘activate’, pnSubscribe); // and listen to incomming push notifications self.addEventListener(‘push’, pnPopupNotification); // … and listen to the click self.addEventListener(‘notificationclick’, pnNotificationClick);

2.1.4.1. Subscribe to push notifications and send subscription to the server

In the listener of the ‘activate’ event, the notification is subscribed using the web push API. The public VAPID key (see 1.2.3.) is required for this. In addition, the function requires the boolean value ‘userVisibleOnly’ as parameter, which must always be set to true.

Comment on this parameter
When designing the web push API, there was a consideration if this parameter can be used to control whether a message generally has to be displayed to the user or whether certain actions can only be carried out in the background.

However, there were concerns that this would create the possibility for developers to perform unwanted actions without the user’s knowledge. This parameter can therefore be regarded as a ‘silent agreement’ that the user always get a message when a push notification arrives.async function pnSubscribe(event) { console.log(‘Serviceworker: activate event’); try { var appPublicKey = encodeToUint8Array(strAppPublicKey); var opt = { applicationServerKey: appPublicKey, userVisibleOnly: true }; self.registration.pushManager.subscribe(opt) .then((sub) => { // subscription succeeded – send to server pnSaveSubscription(sub) .then((response) => { console.log(response); }).catch ((e) => { // registration failed console.log(‘SaveSubscription failed with: ‘ + e); }); }, ).catch ((e) => { // registration failed console.log(‘Subscription failed with: ‘ + e); }); } catch (e) { console.log(‘Error subscribing notifications: ‘ + e); } }

The public VAPID key must be transferred to the push manager as a UInt8 array. If successful, the push manager returns a subscription object. This object contains all information the server needs in addition to its own VAPID keys to be able to encrypt and send push notifications to this client. For this purpose, the information received must be sent to the server.

The data is sent to the server as JSON-formatted text in the body of a POST HTTP request. For transmission, we use the fetch() method of the javascript Fetch API. This method allows resources easily to be accessed or sent asynchronously over the network.async function pnSaveSubscription(sub) { // stringify object to post as body with HTTP-request var fetchdata = { method: ‘post’, headers: { ‘Content-Type’: ‘application/json’ }, body: JSON.stringify(sub), }; // we’re using fetch() to post the data to the server var response = await fetch(strSubscriberURL, fetchdata); return response.json(); }

The target ‘strSubscriberURL’ is a service that has to be provided on your server. It accepts the transmitted data and stores it in a database. The implementation of this service is described in section 2.2.

If additional specific information is required in addition to the current subscription (e.g. login data of the user, a reference to a specific order or reservation, …), this should also be transferred here, since this is the only direct link between client and server.

2.1.4.2. Displaying the received PUSH notifications

In contrast to the server side, on the client side the web push API (and the push services) takes over all tasks regarding verification and decryption, which enables us to concentrate on the display of the notification.

When a push notification arrives, a corresponding ‘push’ event is triggered to the service worker. So the first thing to do is to set up a listener to this event. All relevant information is passed to the listener in the ‘event’ parameter.

In addition to some internal properties, this object primarily contains the data sent by the server. The format in which the data is transmitted is the sole responsibility of the sender. At this point, pure text is assumed – this may also can be sent for test purposes from some tools or from some browsers developer tools. (See appendix).

After we have implemented the sending of the notifications in chapter 2.3. we will switch to an object encoded as a JSON string. Through this object we are able to control most of the properties of the notification to be displayed. First of all, it’s just about displaying a simple text message.function pnPushNotification(event) { console.log(‘push event: ‘ + event); var strTitle = ‘Notification’; var strText = ’empty Notification received!’; if (event.data) { strText = event.data.text(); } var promise = self.registration.showNotification(strTitle, opt); event.waitUntil(promise); }

To display the message the showNotification() function have to be used, which is passed the title and an option object. This option object can contain properties to control the content, format and behavior of the notification.

A more detailed description follows in Chapter 2.3 when notifications are sent from the server. The final call of waitUntil() ensures that the (asynchronously generated) notification was actually displayed before the function exits and the browser terminates the service-worker.

2.1.4.3. Respond to user actions

In order to be able to react to user actions, a listener for the ‘notificationclick’ event must be set up. With the ‘event’ parameter, this function receives all data for the notification in the ‘event.notification’ property. User-specific data can be passed within ‘event.notification.data’. This data for example can contain an URL to be opened when the user clicks on the notification.function pnNotificationClick(event) { console.log(‘notificationclick event: ‘ + event); if (event.notification.data && event.notification.data.url) { const promise = clients.openWindow(event.notification.data.url); event.waitUntil(promise); } }

The function clients.openWindow() is available for opening a URL in the browser. Here, too, the waitUntil() must be used to wait for the call to end correctly before the service-worker can be terminated.

Further possible actions inside of the ‘notificationclick’ event are discussed in chapter 2.3 when messages are sent from the server.

2.2. Receive and save subscriptions on the server

To receive and save the subscriptions, a service is set up on the server that receives the data posted by the HTTP request from the client and stores it in a database. It must therefore first be checked whether it is a POST request. In addition, it must be checked whether the content of the request has actually been identified as JSON data.

If the request is correct, the data will be saved. For the sake of simplicity, we use a SQLite data provider here, since it creates its own data file and can be used without further configuration. By using the same data provider, the subscriptions will be accessed later to send the notifications. 

To integrate the package into your own system, you can use the MySQL data provider or your own data provider that implements the PNDataProvider interface.
// only serve POST request containing valid json data if (strtolower($_SERVER[‘REQUEST_METHOD’]) == ‘post’) { if (isset($_SERVER[‘CONTENT_TYPE’]) && trim(strtolower($_SERVER[‘CONTENT_TYPE’]) == ‘application/json’)) { // get posted json data if (($strJSON = trim(file_get_contents(‘php://input’))) === false) { $result[‘msg’] = ‘invalid JSON data!’; } else { $oDP = new PNDataProviderSQLite(); if ($oDP->saveSubscription($strJSON) !== false) { $result[‘msg’] = ‘subscription saved on server!’; } else { $result[‘msg’] = ‘error saving subscription!’; } } } else { $result[‘msg’] = ‘invalid content type!’; } } else { $result[‘msg’] = ‘no post request!’; } // let the service-worker know the result echo json_encode($result);

2.3. Create and send notifications

To send push notifications we have to follow the definitions of the web push protocol (see https://tools.ietf.org/html/draft-ietf-webpush-protocol-12). Basically, two steps are necessary when creating the push notification.

In order to identify yourself with the push service, a signature must be transferred using the VAPID key in the header of the request. The notification itself is transmitted in encrypted form and corresponding information is also passed in the header so that the browser can decrypt the received data. If the notification was decrypted correctly, the browser triggers the ‘push’ event to the service-worker.

2.3.1. The VAPID header

In order to identify with the push service, the server has to sign some information in JSON format with its private VAPID key and pass it in the header. The push service verifies this and, if successful, forwards the notification to the user.

The signature is given in the form of a JSON Web Token (JWT). A signed JWT is nothing more than a string, which consists of three components separated by dots:

JWTInfo . JWTData . Signature

The first two strings are JSON formatted data, which have to be ‘URL safe base64’ encoded, the third part contains the encrypted signature.

JWT Info

This contains information about the JWT itself and the encryption algorithm used.

JWT Data

Contains information about the sender, the recipient (not the final recipient, but the push service!) and how long the message is valid.

Signature

The signature is generated from the first two unsigned parts. To do this, they are encrypted with the ES256 algorithm (short for: ECDSA using the P-256 curve and the SHA-256 hash algorithm) using the VAPID key.

The push service now validate the JWT by decrypting the signature using the public VAPID key and comparing it with the first two parts.

The complete JWT (i.e. all three parts separated by a dot) is passed as authorization in the header. In addition, the public VAPID key ‘URL safe base64’ coded must be transferred in the crypto-key value.

The required VAPID headers are generated with the PNVapid class. The VAPID keys are passed once in the constructor since they do not change. The end point (i.e. the recipient) is passed on again for each notification to be generated.
// info $aJwtInfo = array(‘typ’ => ‘JWT’, ‘alg’ => ‘ES256’); $strJwtInfo = self::encodeBase64URL(json_encode($aJwtInfo)); // data // – origin from endpoint // – timeout 12h from now // – subject (e-mail or URL to invoker of VAPID-keys) $aJwtData = array( ‘aud’ => PNSubscription::getOrigin($strEndpoint), ‘exp’ => time() + 43200, ‘sub’ => $this->strSubject ); $strJwtData = self::encodeBase64URL(json_encode($aJwtData)); // signature // ECDSA encrypting “JwtInfo.JwtData” using the P-256 curve // and the SHA-256 hash algorithm $strData = $strJwtInfo . ‘.’ . $strJwtData; $pem = self::getP256PEM($this->strPublicKey, $this->strPrivateKey); if (\openssl_sign($strData, $strSignature, $pem, ‘sha256’)) { if (($sig = self::signatureFromDER($strSignature)) !== false) { $strSignature = self::encodeBase64URL($sig); $aHeaders = array( ‘Authorization’ => ‘WebPush ‘ . $strJwtInfo . ‘.’ . $strJwtData . ‘.’ . $strSignature, ‘Crypto-Key’ => ‘p256ecdsa=’ . self::encodeBase64URL($this->strPublicKey) ); } }

2.3.2. Encrypt the payload

Since the push notifications are sent by various push service providers, the actual user data is transmitted in encrypted form. The push service is unable to decrypt and read this data.

This is defined in the ‘Message Encryption for Web Push’ (see https://tools.ietf.org/html/draft-ietf-webpush-encryption-09).

The techniques that are used during encryption are beyond the scope of this tutorial and are therefore not explained in detail. You will find a good explanation in the web push book by Matt Gaunt (https://web-push-book.gauntface.com) in chapter 4.2.

All required functions are provided by the PNEncryption class. This class also provides the additional request headers that are required so that the notification can be decrypted. In the constructor, this class requires the public key and the authentication code that was generated by the browser when subscribing, and of course the user data to be encrypted.

2.3.3. The payload

At this point we are now going to take a closer look at the user data that we want to send with the notification. As mentioned in section 2.1.4, the possible options that can be passed to the showNotification() function in the service-worker are explained in more detail now.

Since the format and content of the payload can be freely defined (as long as the length of the user data does not exceed approx. 4000 characters), I have decided to include all information for displaying the notification on the server side together in an object. In addition to the title and the target URL to which we want to direct the user, this object also contains the complete options for the showNotification() function.

Everything together is then JSON-encoded and sent as payload. This gives us the greatest flexibility to determine the display and behavior of the notification from PHP without having to make changes to the service worker.

2.3.3.1. The options of showNotification()

In order to address the user with a clear notification, this should consist at least of a short, meaningful title, a symbol with recognition value (-> preferably a company or product logo) and a short, precise text.

The title is passed directly as a parameter, the other two values are part of the option object. A clear recommendation regarding the format of the symbol cannot be made. In any case, a square format should be chosen, since most browsers or platforms crop other formats accordingly.

A size of 64dp (px * device pixel ratio – this gives 192px for a value of 3) has proven itself. The text should not be longer than about 200 characters. Here, too, the browsers and platforms differ in behaviour when a longer text is provided. Some limit the text to a certain number of characters, others to a certain number of lines. It should also be keep in mind here that a text that is too long usually does not receive the necessary attention from the user.

With the ‘tag’ option, notifications can be grouped for the user. This ensures that only the most recently received notifications with the same indicator are displayed to the user so he will not be “flooded” with a sequence of several messages of the same type. If the ‘renotify’ option is also set, the user will be notified, and the notifications will still be grouped in the display list. If not set, no notification will be displayed.

The support of the following properties, which can be defined to format the notification or its behaviour, varies widely between the several browsers/platforms and should therefore be used with caution.

Image

URL to a larger image, which is usually displayed below the text. Again, it is difficult to give a rule about size or format.

Badge

URL to a (often monochrome) badge. The badge is used to better classify the sender of the message. So far, this is only supported by a few browsers – most of them display their own icon.

Additional actions

Some browsers allow certain actions to be displayed within the notification so the user can select one of it. The respective javascript code must be defined in the service worker in the ‘notificationclick’ event. If this functionality is used, an alternative display and handling should always be provided if the browser or the target system does not support this function.

An action is defined by:
– action:    internal ID used in ‘notificationclick’ event.
– title:        text to be displayed.
– icon:       [optional] URL to an icon assigned to the action.

The count of actions that can be displayed within a notification vary as well. An interesting article on this topic can be found at https://developers.google.com/web/updates/2016/01/notification-actions.

Timestamp

This allows you to set the time when the message was generated. If this option is not set, the time at which the message arrived at the user is set.

Require Interaction

This property specifies that user interaction is required for the notification. The popup is usually displayed immediately and disappears after a certain time. If this option is activated, the popup remains until the user answers. This property should be used carefully (for very important or security issues only) as the user may find it annoying and may block the notifications permanently.

Silent

No sound is played or vibration is triggered.

Vibrate

A vibration pattern to run with the display of the notification. A vibration pattern must be an array with at least one member. The values are times in milliseconds where the even indices (0, 2, 4, etc.) indicate how long to vibrate and the odd indices indicate how long to pause. For example, [300, 100, 400] would vibrate 300ms, pause 100ms, then vibrate 400ms.

Sound

URL to a sound file. So far I have not found a browser that supports this.

2.3.3.2. Extend the ‘push’ event listener in the service-worker

To generate the notification, the PNPayload class provides all methods to define the properties described and create the Object.

Since we initially assumed pure text as user data when creating the service-worker in section 2.1.4, the event listener must now be expanded for the data contained in the notification. All that needs to be done is to decode the received JSON-formatted data and pass it on when calling the showNotification() function.
function pnPushNotification(event) { console.log(‘push event: ‘ + event); var strTitle = strDefTitle; var oPayload = null; var opt = { icon: strDefIcon }; if (event.data) { // PushMessageData Object containing the pushed payload try { // try to parse payload JSON-string oPayload = JSON.parse(event.data.text()); } catch (e) { // if no valid JSON Data take text as it is… // … comes maybe while testing directly from DevTools opt = { icon: strDefIcon, body: event.data.text(), }; } if (oPayload) { if (oPayload.title != undefined && oPayload.title != ”) { strTitle = oPayload.title; } opt = oPayload.opt; if (oPayload.opt.icon == undefined || oPayload.opt.icon == null || oPayload.icon == ”) { // if no icon defined, use default opt.icon = strDefIcon; } } } var promise = self.registration.showNotification(strTitle, opt); event.waitUntil(promise); }

2.3.4. Send the notification via Http-request

The last step is to send the notification(s) to the respective push services via HTTP request. In order to be as independent as possible, this is done directly using cURL.

To have as little idle time as possible even with a large number of notifications to be sent, all pending messages are first generated completely, encrypted and then sent using a cURL Multirequest.

Since PHP does not support multithreading per se, this is the most elegant solution without complex external PHP extensions. After all notifications have been sent, the response codes of all requests are read in order to filter out any subscriptions that are no longer valid and, if so configured, to delete them from the database.

The complete process to send notifications

  • create the VAPID header signature
  • generate the notification payload
  • encrypt the payload
  • send via HTTP request
  • If necessary, delete expired / no longer valid subscriptions

is implemented in PNServer by using the respective classes.

3. Appendix

3.1. How long is a Subscription valid?

In principle, the information provided by the browser for a subscription also contains a time stamp when it expires. Almost no browser assigns a valid value to this data field (a correct value only was set by MS Edge).

According to the specification for subscriptions that have an expiration date, the push service sends a ‘pushsubscriptionchange’ event to the corresponding service-worker before the expiration. In this case, the service-worker should re-subscribe the notifications.

If a user quit an existing subscription (generally by blocking the notifications for the page in the browser), this is forwarded by the browser to the corresponding push service. If the server then tries to send a notification to this endpoint it is not forwarded to the browser but the push service send a response code of 410 back to the server instead.

For those cases, the Notification Server has the option of removing subscriptions that are no longer valid from its database in order to avoid unnecessary data traffic.

However, if a browser is no longer in use, uninstalled or the system is no longer used for another reason (reinstallation, outdated, defective), the existing subscriptions that do not have an expiry date are retainedin the database.

The W3C and standard browser providers are considering getting this problem under control. Unfortunately, the notification server itself doesn’t have a reliable way to detect inactive subscriptions.

3.2. Standardbrowser settings to display notifications

Most (desktop) standard browsers offer the option of setting whether a service provided by the operating system or an own implementation should be used to display the notifications.

3.2.1. Firefox

Type ‘about:config’ in the navigation field for the Internet URL and search for ‘alerts’. The value ‘alerts.useSystemBackend’ controls the behaviour. If set to true, notifications are displayed by the operating system, otherwise the browsers internal implementation is used to display the notifications.

3.2.2. Google Chrome

Enter ‘chrome://flags’ in the navigation field for the Internet URL and then search for ‘notifications’. The setting ‘Enable native notifications’ controls the output.

3.2.3. Microsoft Edge

Since the Edge Browser is very much integrated into the Windows operating system, it basically uses the Control Center to display the notifications.

3.3. Debugging and testing the service-workers

There are various options for debugging and testing the service-worker in the developer tools of the standard browsers.

3.3.1. Firefox

Type ‘about:debugging#/runtime/this-firefox’ in the navigation field for the Internet URL. All registered service-workers are displayed below the list of the extensions.

The service-worker can be started or logged off here. Once the service worker is started, an (empty…) test message can be pushed, or the console and debugger of the service-worker can be opened.

3.3.2. Google Chrome

Open the developer tools when the page from which the notifications are subscribed is open. The registered service-worker is displayed under the menu item ‘Application’. Here you can start, stop, update or unregister the service-worker. A test message can also be sent and you can switch to the source code / debugger.

3.3.3. Microsoft Edge

Similar to Chrome, MS Edge has a item in the main menu of the developer tools named ‘Serviceworker’.

4. Conclusion

Web push notifications are a great means to keep users coming to a site that publishes content that they like.

Implementing Web push notifications using PHP and JavaScript it is not hard. It requires some work but the package PHP Web Push Notifications Server was created to simplify this jobs.

You can download or install this package using PHP Composer tool by going to this download page to get the package code.


Good Luck!

HTML in PHP for Beginners

PHP is an HTML-embedded server-side scripting language. Much of its syntax is borrowed from C, Java and Perl with a couple of unique PHP-specific features thrown in. The goal of the language is to allow web developers to write dynamically generated pages quickly. NTC Hosting offers its clients high quality PHP and HTML hosting servicesOur servers are configured so as to ensure maximum performance for both your HTML and PHP-based applications and the non-interruptible functioning of your websites.Content:

PHP in HTML

When building a complex page, at some point you will be faced with the need to combine PHP and HTML to achieve your needed results. At first point, this can seem complicated, since PHP and HTML are two separate languages, but this is not the case. PHP is designed to interact with HTML and PHP scripts can be included in an HTML page without a problem.

In an HTML page, PHP code is enclosed within special PHP tags. When a visitor opens the page, the server processes the PHP code and then sends the output (not the PHP code itself) to the visitor’s browser. Actually it is quite simple to integrate HTML and PHP. A PHP script can be treated as an HTML page, with bits of PHP inserted here and there. Anything in a PHP script that is not contained within <?php ?> tags is ignored by the PHP compiler and passed directly to the web browser. If you look at the example below you can see what a full PHP script might look like:

Recommended usage:

<head></head>
<body class=”page_bg”>
Hello, today is <?php echo date(‘l, F jS, Y’); ?>.
</body>
</html>

The code above is simply HTML, with just a bit of PHP that prints out today’s date using the built-in date function. As mentioned above, all of the plain HTML in the code above will be ignored by the PHP compiler and passed through to the web browser untouched.

See how easy that is? Integrating PHP and HTML is really very simple. Just remember that at its core, a PHP script is just an HTML page with some PHP sprinkled through it. If you want, you can create a PHP script that only has HTML in it and no <?php ?> tags, and it will work just fine.

More advanced techniques:

<html>
<head></head>
<body>
<ul> 
<?php for($i=1;$i<=5;$i++){ ?>
<li>Menu Item <?php echo $i; ?></li> 
<?php } ?>
</ul> 
</body>
</html>

and the result is:

  • Menu Item 1
  • Menu Item 2
  • Menu Item 3
  • Menu Item 4
  • Menu Item 5

PHP in HTML using short_open_tag

If you want to shorten your code as much as possible, you can go for the short_tags option. This will save you from typing <?php at the beginning of the code, shortening it to just <?. In order to enable this, you should update the php.ini file and turn the “short_tags” setting from “Off” to “On”. While on most servers this setting is already turned on, it’s always best to check beforehand. A problem that can occur if using short tags is a conflict with the XML usage. For XML, the <? syntax will start a processing function. To avoid this problem, the alternative <?= tag can be used.

PHP in HTML using short_tags:

<html>
<head></head>
<body class=”page_bg”>
Hello, today is <?=date(‘l, F jS, Y’); ?>.
</body>
</html>

Have in mind that if you want to build a website compatible with as many platforms as possible, you should not rely on short_tags.

HTML in PHP using echo

A possible way to integrate HTML tags in a PHP file is via the echo command:

Possible yet not recommended usage:

<?php
echo “<html>”;
echo “<head></head>”;
echo “<body class=\”page_bg\”>”;
echo “Hello, today is “;
echo date(‘l, F jS, Y’); //other php code here echo “</body>”;
echo “</html>”;
?>

This will, however, affect the HTML Code Coloring option in most HTML/PHP editors, which allows for easy understanding of the role of HTML tags. You should escape each double quote within the HTML code with a backslash.

PHP in HTML – file extensions

When a given file contains PHP code, it must have a PHP extension. In most cases this is .php, but you can also configure the .htaccess file to read the PHP code in the HTML file without renaming it or changing its extension. Below you can view the “handlers”, which will have to be added in order to achieve this

For a normally configured web server:

AddHandler cgi-script .html .htm

A web server running FastCGI:

AddHandler fcgid-script .html .htmNote: this is tested and works with the NTC web hosting servers. If you are using a different hosting provider, consult them for assistance. Additionally, if you are faced with constant problems there, you can consider switching to NTC Hosting in order to get the PHP optimized stable servers you need.

HTML in PHP

You can also use HTML code in a PHP script. This can be very useful if you have built your whole page in PHP, but want to include a custom HTML form, for example. All that you need to do is reverse the order of the HTML and PHP opening tags, opening the page with PHP:

Using HTML in PHP:

<?php
$Fname = $_POST[“Fname”];
$Lname = $_POST[“Lname”];
?>
<html>
<head>
<title>Personal INFO</title>
</head>
<body>
<form method=”post” action=”<?php echo $PHP_SELF;?>”>
First Name:<input type=”text” size=”12″ maxlength=”12″ name=”Fname”><br />
Last Name:<input type=”text” size=”12″ maxlength=”36″ name=”Lname”><br /></form>
<?
echo “Hello, “.$Fname.” “.$Lname.”.<br />”;
?>

While this looks a bit complicated, it actually saves you a lot of code. Here, we are using the $PHP_SELF super global, which allows us to use the value of the fields, specified under it, in the same file. Usually, for such forms two files are created – the first one is the HTML form itself and the second one is the backend PHP file, which does all the work.

If you already have a complicated PHP application, which relies on a great number of files, and you just want to keep everything as simple as possible, this can be of great assistance.

PHP with NTC Hosting

NTC Hosting offers its clients an ultimate web hosting solution. All our web hosting plans provide support for HTML and give you the possibility to choose between PHP4and PHP5

Testing PDF content with PHP and Behat

If you have a PDF generation functionality in your app, and since most of the libraries out there build the PDF content in an internal structure before outputting it to the file system (FPDF, TCPDF). A good way to write a test for it is to test the output just before the rendering process.

Recently however, and due to this process being a total pain in the ass, people switched to using tools like wkhtmltopdf or some of its PHP wrappers (phpwkhtmltopdfsnappy) that let you build your pages in html/css and use a browser engine to render the PDF for you, and while this technique is a lot more developer friendly, you loose control over the building process.

So if you’re using one of those tools or just need to test for the existence of some string inside a PDF, here’s how to write a BDD style acceptance test for it using Behat.

Setup framework

Add this your composer.json then run composer install

{
    "minimum-stability": "dev",
    "require": {
        "smalot/pdfparser": "*",
        "behat/behat": "3.*@stable",
        "behat/mink": "1.6.*@stable",
        "phpunit/phpunit": "4.*"
    },
    "config": {
        "bin-dir": "bin/"
    }
}

Initialize Behat

bin/behat --init

This command creates the initial features directory and a blank FeatureContext class.

If everything worked as expected, your project directory should look like this :

├── bin
│   ├── behat -> ../vendor/behat/behat/bin/behat
│   └── phpunit -> ../vendor/phpunit/phpunit/phpunit
├── composer.json
├── composer.lock
├── features
│   └── bootstrap
└── vendor
    ├── autoload.php
    ├── behat
    ├── composer
    ├── doctrine
    ├── phpdocumentor
    ├── phpspec
    ├── phpunit
    ├── sebastian
    ├── smalot
    ├── symfony
    └── tecnick.com

All right, it’s time to create some features, create a new file inside /feature, I’ll name mine pdf.feature

Feature: Pdf export
 
  Scenario: PDF must contain text
    Given I have pdf located at "samples/sample1.pdf"
    When I parse the pdf content
    Then the the page count should be "1"
    Then page "1" should contain
    """
Document title  Calibri : Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    """

Run Behat (I know we didn’t write any testing code yet, just run it, trust me!)

bin/behat

An awesome feature of Behat is it detects any missing steps and provides you with boilerplate code you can use in your FeatureContext. This is the output of the last command:

Feature: Pdf export
 
  Scenario: PDF must contain text                     # features/pdf.feature:3
    Given I have pdf located at "samples/sample1.pdf"
    When I parse the pdf content
    Then the the page count should be "1"
    Then page "1" should contain
      """
      Document title  Calibri : Lorem ipsum dolor sit amet, consectetur adipiscing elit.
      """
 
1 scenario (1 undefined)
4 steps (4 undefined)
0m0.01s (9.28Mb)
 
--- FeatureContext has missing steps. Define them with these snippets:
 
    /**
     * @Given I have pdf located at :arg1
     */
    public function iHavePdfLocatedAt($arg1)
    {
        throw new PendingException();
    }
 
    /**
     * @When I parse the pdf content
     */
    public function iParseThePdfContent()
    {
        throw new PendingException();
    }
 
    /**
     * @Then the the page count should be :arg1
     */
    public function theThePageCountShouldBe($arg1)
    {
        throw new PendingException();
    }
 
    /**
     * @Then page :arg1 should contain
     */
    public function pageShouldContain($arg1, PyStringNode $string)
    {
        throw new PendingException();
    }

Cool right? copy/paste the method definitions to you FeatureContext.php and let’s get to it, step by step :

Step 1

Given I have pdf located at "samples/sample1.pdf"

In this step we only need to make sure the filename we provided is readable then store it in a class property so we can use it in later steps:

 /**
     * @Given I have pdf located at :filename
     */
    public function iHavePdfLocatedAt($filename)
    {
        if (!is_readable($filename)) {
            Throw new \InvalidArgumentException(
                sprintf('The file [%s] is not readable', 
                $filename)
            );
        }
 
        $this->filename = $filename;
    }

Step 2

When I parse the pdf content

The heavy lifting is done here, we need to parse the PDF and store its content and metadata in a usable format:

    /**
     * @When I parse the pdf content
     */
    public function iParseThePdfContent()
    {
        $parser = new Parser();
        $pdf    = $parser->parseFile($this->filename);
        $pages  = $pdf->getPages();
        $this->metadata = $pdf->getDetails();
 
        foreach ($pages as $i => $page) {
            $this->pages[++$i] = $page->getText();
        }
    }

Step 3

Then the the page count should be "1"

Since we already know how many pages the PDF contains, this is a piece of cake, so let’s not reinvent the wheel and use PHPUnit assertions:

 /**
     * @Then the the page count should be :pageCount
     * @param int $pageCount
     */
    public function theThePageCountShouldBe($pageCount)
    {
        PHPUnit_Framework_Assert::assertEquals( 
            (int) $pageCount, 
            $this->metadata['Pages']
        );
    }

Step 4

Then page "1" should contain
    """
Document title  Calibri : Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    """

Same method, we have an array containing all content from all pages, a quick assertion does the trick:

    /**
     * @Then page :pageNum should contain
     * @param int $pageNum
     * @param PyStringNode $string
     */
    public function pageShouldContain($pageNum, PyStringNode $string)
    {
        PHPUnit_Framework_Assert::assertContains(
            (string) $string, 
            $this->pages[$pageNum]
        );
    }

Et voilà! you should have green

Feature: Pdf export
 
  Scenario: PDF must contain text                     # features/pdf.feature:3
    Given I have pdf located at "samples/sample1.pdf" # FeatureContext::iHavePdfLocatedAt()
    When I parse the pdf content                      # FeatureContext::iParseThePdfContent()
    Then the the page count should be "1"             # FeatureContext::theThePageCountShouldBe()
    Then page "1" should contain                      # FeatureContext::pageShouldContain()
      """
      Document title  Calibri : Lorem ipsum dolor sit amet, consectetur adipiscing elit.
      """
 
1 scenario (1 passed)
4 steps (4 passed)

For the purpose of this article, we’re relying on the PDF parser library which has many encoding and white space issues, feel free to use any PHP equivalent or a system tool like xpdf for better results.

If you want to make your test more decoupled (and you should). One way is to create a PDFExtractor interface then implement it for each tool you want to use, that way you can easily swap libraries.

The source code behind this article is provided here, any feedback is most welcome.

Source: matmati.net:80/testing-pdf-with-behat-and-php