Send dynamic email from HTML & CSS template – PHP

By the end of this tutorial, you will be able to send a dynamic email in PHP. Along with any beautifully designed template in HTML, CSS or Bootstrap. We will be using the template named “Invoice” from this website:
https://www.dyspatch.io/resources/templates/airmail/

It’s a pretty basic template and great to learn.
After downloading the template, you will see something like this:

All are static values. So let’s make them dynamic.

First you have to put all the template code in 1 separate file and named it “payment.php”, make sure to have all CSS code in this file. No external CSS file should be used because it will not appear in email.

Now, you have to replace the values you want to change and replace them with {{key}} for example, if you want to make coupon code dynamic, you will do something like this:

Coupon code {{coupon_code}}

Now, coming back to the file from where you want to send email, let’s say “send-mail.php”, first you have to get the template file by:

<?php
    $email = file_get_contents("payment.php");
    echo $email;
?>

This will display your email template in “send-mail.php” file. In order to replace the {{coupon_code}} with your dynamic value, you have to use the str_replace function of PHP. It accepts 3 parameters:

  1. Value to be replaced
  2. New value
  3. String from which to replace
<?php
    $email = file_get_contents("payment.php");
    $email = str_replace("{{coupon_code}}", "1234567", $email);
    echo $email;
?>

Now we are going to add {{key}} on every static value in template which needs to be dynamic. After that, you need to create an array in your “send-mail.php” file and use the same function for all static values.

<?php
    $email = file_get_contents("payment.php");
    $email = str_replace("{{coupon_code}}", "1234567", $email);
    $variables = array(
        "{{coupon_code}}" => 1234,
        "{{invoice}}" => 5678,
        "{{card_ending}}" => 9876,
        "{{username}}" => "Adnan"
   );

    foreach ($variables as $key => $value)
        $email = str_replace($key, $value, $email);
    echo $email;
?>

Now, you will be able to see your template with correct values. You can send the mail using the following 2 methods:

  1. PHP built-in mail() function
  2. Using PHPMailer library

Built-in mail() function

You can call the function:

<?php
    // Your subject goes here
    $subject = 'Payment Invoice';

    $headers = "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";

    // Enter receiver's email address
    mail("receiver_email@gmail.com", $subject, $email, $headers);
?>

Using PHPMailer library

You can install the library using composer in your project:

composer require phpmailer/phpmailer

and follow the guide from here: https://github.com/PHPMailer/PHPMailer


If you do not want to use composer, you can download manually from the following link and follow the guide: https://github.com/adnanafzal565/php-mailer

Hit the “send mail” button and you will receive an email similar to this:

So that’s how you can send a dynamic email in PHP from any HTML template. Also, learn how you can attach a link to the file to download in an email from here.

If you have any problems in following this, feel free to ask in the comments section below.

[wpdm_package id=’76’]

How to upload single and multiple images in iOS Swift, PHP and MySQL

In this article, we will discuss how you can upload single or multiple images from your iOS app in Swift, and save them in the MySQL database.

Solution for Swift UI

If you are developing your app in Swift UI, please follow this post.

When developing iOS applications, one of the most common features in almost all apps is to upload images. It can be in the form of a profile picture, or payment receipt or anything. Swift provides a built-in method to allow developers to add functionality. There users can select an image from their photo library. However, to upload multiple images, there is no built-in method in Swift at the time of writing this. But we have external libraries that allow users to pick multiple images.

Save image from iOS app

When it comes to saving the image in the database, there are again multiple choices. You can either convert the image in an encoded base64 string or you can send an image entirely as multipart. The second choice is not very often used because it has some drawbacks. The major one of them is that the image with very high quality and large size are unable to transfer. So we will choose the first method i.e. to convert an image into an encoded base64 string.

1. Single image upload

In this method, no external library has been used. All the functions required to select single image from gallery are already provided by Swift. We just need to implement 2 delegates UIImagePickerControllerDelegate and UINavigationControllerDelegate to our view controller that will be responsible to open the screen to gallery and also to return the selected image. We have created a simple button which when clicked will open the UIImagePickerController in current view controller. imagePickerController this is a delegate function present in UIImagePickerControllerDelegate that will return the selected image from photo library. We are displaying that image in our UIImageView for confirmation, and also to send to the server. Because we can convert an image to base64 string using its UIImageView object.

Then we are creating a button which when clicked will convert the image to base64 string and send the request to the server. For sending an HTTP request, you also have many choices, for example, you can use the Alamofire library. But to keep things simple, we are using Swift’s built-in NSURLConnection class. Before sending the request we are also displaying a loading dialog and when the response is received from the server, we are simply displaying an alert that the image has been uploaded.

Swift iOS

import UIKit

class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    private var image: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let btnSelectImage: UIButton = UIButton(frame: CGRect(x: 30, y: 100, width: view.frame.size.width - 60, height: 30))
        btnSelectImage.setTitle("Select image", for: .normal)
        btnSelectImage.setTitleColor(UIColor.systemBlue, for: .normal)
        btnSelectImage.contentHorizontalAlignment = .center
        btnSelectImage.addTarget(self, action: #selector(selectImage), for: .touchUpInside)
        view.addSubview(btnSelectImage)
        
        image = UIImageView(frame: CGRect(x: 30, y: btnSelectImage.frame.origin.y + btnSelectImage.frame.size.height + 30, width: 300, height: 300))
        image.clipsToBounds = true
        image.contentMode = .scaleAspectFill
        view.addSubview(image)
        
        let btnUpload: UIButton = UIButton(frame: CGRect(x: 30, y: image.frame.origin.y + image.frame.size.height + 30, width: view.frame.size.width - 60, height: 40))
        btnUpload.setTitle("Upload to server", for: .normal)
        btnUpload.backgroundColor = UIColor.systemGreen
        btnUpload.setTitleColor(UIColor.white, for: .normal)
        btnUpload.addTarget(self, action: #selector(uploadToServer), for: .touchUpInside)
        btnUpload.layer.cornerRadius = 5
        view.addSubview(btnUpload)
    }
    
    @objc private func uploadToServer(sender: UITapGestureRecognizer) {
        let imageData: Data = image.image!.pngData()!
        let imageStr: String = imageData.base64EncodedString()

        let alert = UIAlertController(title: "Loading", message: "Please wait...", preferredStyle: .alert)
        present(alert, animated: true, completion: nil)

        let urlString: String = "imageStr=" + imageStr
        
        var request: URLRequest = URLRequest(url: URL(string: "http://172.20.10.2:8888/tutorials/single-multiple-image-upload/index.php")!)
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        request.httpBody = urlString.data(using: .utf8)

        NSURLConnection.sendAsynchronousRequest(request, queue: .main, completionHandler: { (request, data, error) in

            guard let data = data else {
                return
            }

            let responseString: String = String(data: data, encoding: .utf8)!
            print("my_log = " + responseString)

            alert.dismiss(animated: true, completion: {

                let messageAlert = UIAlertController(title: "Success", message: responseString, preferredStyle: .alert)
                messageAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action: UIAlertAction!) in
                    //
                }))

                self.present(messageAlert, animated: true, completion: nil)
            })
        })
    }
    
    @objc private func selectImage(sender: UITapGestureRecognizer) {
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self as! UIImagePickerControllerDelegate & UINavigationControllerDelegate
        imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
        imagePicker.allowsEditing = false
        present(imagePicker, animated: true, completion: nil)
    }
    
    @objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        let chosenImage = info[UIImagePickerController.InfoKey.originalImage.rawValue] as! UIImage
        image.image = chosenImage
        dismiss(animated: true, completion: nil)
    }

}

PHP & MySQL

Make sure to change the server path with yours. If you are working on localhost, you can get your IP address by command prompt or terminal and running the command: ifconfig. In our PHP file, we are first receiving base64 string in a variable and then creating a path where the image will be stored. We need to create a folder named “images” in our server’s root folder.

Then we need to decode that base64 string into actual image file, so remove the base64 data part from a string, replace all empty spaces with + sign, and then decoding the base64 string, and finally saving the file in the images folder. We also need to save that file’s reference in our database, so we are simply making a connection with MySQL database and running an INSERT query to save the path of the image. Then we are sending the response as a string back to the iOS app. Make sure to change the database credentials as well as per your server.

<?php

$picture = $_POST["imageStr"];
$folder_path = "images/" . time() . ".png";

$data = str_replace('data:image/png;base64,', '', $picture);
$data = str_replace(' ', '+', $data);
$data = base64_decode($data);
file_put_contents($folder_path, $data);

$conn = mysqli_connect("localhost:8889", "root", "root", "tutorials");

$sql = "INSERT INTO images (path) VALUES ('$folder_path')";
mysqli_query($conn, $sql);

echo "Image has been uploaded";

?>

2. Multiple image upload

As discussed earlier, we need to use an external library to implement multiple image features in our iOS app. So we are going to use a library called BSImagePicker. It will be installed in our project using Cocoa pods, first, you need to initialize it. Open command prompt or terminal in your project’s root folder and run the following command:

pod init

This will create a Podfile (without any extension) in your project’s root folder. Open that file and include the library like the following, your project name could be different of course:

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'MultipleImageUpload' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for MultipleImageUpload
  pod "BSImagePicker", "~> 3.1"

end

Now run the command

pod update

to install the library. Once installed, close the project if already opened and now run the project using XCode but with the file ending with “.xcworkspace” NOT “.xcodeproj”. Now accessing the library requires user permission so open your “info.plist” file as source code and paste the following lines at the end of dict tag:

<key>NSPhotoLibraryUsageDescription</key>
<string>Why you want to access photo library</string>

Now open your view controller file and first import 2 files named BSImagePicker and Photos. When user select multiple images we can also show them in a collection view for a better user experience, for that purpose we need to implement 2 delegates, UICollectionViewDelegate and UICollectionViewDataSource. Creating a global variable for collection view so it can be accessible throughout the view controller class, colleection view has multiple cells and each cell has its own identifer and a class. For cell, we have created a class named ImageCell and it has only an image view because that is all we needed here.

Swift iOS

import UIKit

import BSImagePicker
import Photos

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
    
    private var collectionView: UICollectionView!
    private let identifier: String = "identifier"
    private var selectedImages: [UIImage] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let btnSelectImage: UIButton = UIButton(frame: CGRect(x: 30, y: 100, width: view.frame.size.width - 60, height: 30))
        btnSelectImage.setTitle("Select images", for: .normal)
        btnSelectImage.setTitleColor(UIColor.systemBlue, for: .normal)
        btnSelectImage.contentHorizontalAlignment = .center
        btnSelectImage.addTarget(self, action: #selector(selectImages), for: .touchUpInside)
        view.addSubview(btnSelectImage)
        
        let flowLayout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        flowLayout.minimumLineSpacing = 10
        flowLayout.scrollDirection = .horizontal
        flowLayout.minimumInteritemSpacing = 10
        flowLayout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        flowLayout.itemSize = CGSize(width: 300, height: 300)

        collectionView = UICollectionView(frame: CGRect(x: 0, y: btnSelectImage.frame.origin.y + btnSelectImage.frame.size.height + 30, width: view.frame.size.width, height: 300), collectionViewLayout: flowLayout)
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.backgroundColor = UIColor.clear.withAlphaComponent(0)
        collectionView.alwaysBounceHorizontal = true
        collectionView.register(ImageCell.self, forCellWithReuseIdentifier: identifier)
        view.addSubview(collectionView)
        
        let btnUpload: UIButton = UIButton(frame: CGRect(x: 30, y: collectionView.frame.origin.y + collectionView.frame.size.height + 30, width: view.frame.size.width - 60, height: 40))
        btnUpload.setTitle("Upload to server", for: .normal)
        btnUpload.backgroundColor = UIColor.systemGreen
        btnUpload.setTitleColor(UIColor.white, for: .normal)
        btnUpload.addTarget(self, action: #selector(uploadToServer), for: .touchUpInside)
        btnUpload.layer.cornerRadius = 5
        view.addSubview(btnUpload)
    }
    
    @objc private func uploadToServer(sender: UITapGestureRecognizer) {
        let alert = UIAlertController(title: "Loading", message: "Please wait...", preferredStyle: .alert)
        present(alert, animated: true, completion: nil)

        var imageStr: [String] = []
        for a in 0..<self.selectedImages.count {
            let imageData: Data = self.selectedImages[a].jpegData(compressionQuality: 0.1)!
            imageStr.append(imageData.base64EncodedString())
        }

        guard let data = try? JSONSerialization.data(withJSONObject: imageStr, options: []) else {
            return
        }

        let jsonImageString: String = String(data: data, encoding: String.Encoding.utf8) ?? ""
        let urlString: String = "imageStr=" + jsonImageString

        var request: URLRequest = URLRequest(url: URL(string: "http://172.20.10.2:8888/tutorials/single-multiple-image-upload/multiple.php")!)
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        request.httpBody = urlString.data(using: .utf8)

        NSURLConnection.sendAsynchronousRequest(request, queue: .main, completionHandler: { (request, data, error) in

            guard let data = data else {
                return
            }

            let responseString: String = String(data: data, encoding: .utf8)!
            print("my_log = " + responseString)

            alert.dismiss(animated: true, completion: {
                let messageAlert = UIAlertController(title: "Success", message: responseString, preferredStyle: .alert)
                messageAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action: UIAlertAction!) in
                    //
                }))
                self.present(messageAlert, animated: true, completion: nil)
            })
        })
    }
    
    @objc private func selectImages(sender: UITapGestureRecognizer) {
        let imagePicker = ImagePickerController()
        presentImagePicker(imagePicker, select: { (asset) in
        }, deselect: { (asset) in
            
        }, cancel: { (assets) in
            
        }, finish: { (assets) in
            
            self.selectedImages = []
            let options: PHImageRequestOptions = PHImageRequestOptions()
            options.deliveryMode = .highQualityFormat

            for asset in assets {
                PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: options) { (image, info) in
                    self.selectedImages.append(image!)
                    self.collectionView.reloadData()
                }
            }
        })
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return selectedImages.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let data: UIImage = selectedImages[indexPath.item]
        let cell: ImageCell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! ImageCell
        cell.image.image = data
        return cell
    }


}

class ImageCell: UICollectionViewCell {
    var image: UIImageView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupViews()
    }
    
    private func setupViews() {
        image = UIImageView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
        image.clipsToBounds = true
        image.contentMode = .scaleAspectFill
        addSubview(image)
    }
}

PHP & MySQL

As we are sending multiple images in base64 string. So, we have to loop through all and save them one-by-one in the server as well as in MySQL database. The code for this is pretty much same as the previous file.

<?php

$conn = mysqli_connect("localhost:8889", "root", "root", "tutorials");
$imageStr = json_decode($_POST["imageStr"]);

for ($a = 0; $a < count($imageStr); $a++)
{
	$folder_path = "images/" . $a . "-" . time() . ".png";

	$picture = $imageStr[$a];
	$data = str_replace('data:image/png;base64,', '', $picture);
	$data = str_replace(' ', '+', $data);
	$data = base64_decode($data);

	file_put_contents($folder_path, $data);

	$sql = "INSERT INTO images (path) VALUES ('$folder_path')";
	mysqli_query($conn, $sql);
}

echo "Image has been uploaded";

?>

So that’s how you can upload single or multiple images from your iOS app in Swift, and save them in the MySQL database.

[wpdm_package id=’62’]