How to integrate N-Genius payment inline (on WooCommerce checkout) without redirecting to N-Genius page? [closed]

I am working on a custom integration of N-Genius payment gateway in my WordPress + WooCommerce site.

By default, the N-Genius flow redirects the customer to the N-Genius hosted payment page to enter card details.
But I want the payment form (card number, expiry, CVV) to appear inline / on-site / directly on my WooCommerce checkout page — without sending the user to the N-Genius page.

What I have tried:

I am already loading the N-Genius SDK on my checkout page.

I tried rendering the custom card fields, but WooCommerce checkout JavaScript interferes and prevents them from showing.

If I disable WooCommerce checkout scripts, the card fields work fine (but then checkout breaks).

I also attempted moving the N-Genius init script to wp_footer, but still no luck.

Regex to only add missing quotes to HTML attributes?

The Missing Attribute Quotes Problem:

I have HTML emails with clearly copy/pasted code where the original… authors, failed to add double quotes around the values of some HTML attributes. This leads to the parser disregarding those attributes and breaking the emails.

Examples:

  • border=0
  • cellpadding=0
  • cellspacing=0
  • width=480

An example string to be fixed:

<table border=0 style="color: red;" title='Hello'></table>

An example of the string after being fixed:

<table border="0" style="color: red;" title='Hello'></table>

Determining the Regular Expression Logic

I know how to find and replace one or more consecutive characters. What I do not know is how to find and replace two sets of strings in a single regular expression and the whole grouping part:

$string = str_ireplace(array('_','--'),array('-','-'), '$string');

I believe the pattern logic should be:

  1. First if < been encountered but not >? (we are within an element).
  2. Second if the first space is encountered (the element name).
  3. Third if = has been encountered but also the next immediate character is not a quote.
  4. Fourth if after (.*?) (I think, for the value itself) is a space encountered?

Some Attempts:

I’ve been going through pages here on Stack and other websites for a few hours though no one, that I’ve come across, has even bothered to work out the logic forget about working on syntax. So with the logic worked out I have some small parts figured out:

  • preg_replace('/<(.*?)( )/u', '', $s) will replace the element (regardless of it’s tag name) but delete everything up to the first attribute. So I don’t know how to write “do nothing here but make sure it exists” so we’re only applying the expression to attributes assuming the HTML author at least got the < and > formatting correct.
  • preg_replace('/^=(.*?)( )$/u', '', $s) was my attempt to ^ start a match at = and end $ it with a space however this just deletes the entire string.

I can’t get the second part figured out. Then I presume there is a way to group the two individual expressions together.

Question:

How do I update my regular expression to append double quotes to HTML attributes only if they’re missing quotes?

Clarifications:

  1. I absolutely do not want to do anything else with regular expressions here. I believe my goal is reasonably simple (as opposed to something very expansive like this). I figured that the pattern is established enough and possibly not too complex for others with greater experience with regular expressions than I. If I can’t figure this out or get enough help I can just write my own parser just to resolve this issue.
  2. I attempted to use $dom = new DOMDocument; $dom->loadHTML($html); $xml = trim($dom->saveXml($dom)); and that did add the missing quotes, but this is HTML from email that triggered tons of errors from other malformed syntax problems so ultimately it was an interesting though non-viable approach.
  3. To keep it as simple as possible I’m content to ignore single quotes.
  4. If this gets figured out I should be able to easily adapt this to make a second version to replace single quotes with double quotes (or vice-versa) for parsing consistency.

Why Upon failure SQS does not place the failed message upon DLQ?

I am running this worker:

php -d memory_limit=-1 bin/console messenger:consume sqs_channel_manager -vv

And worker fails:

14:29:32 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
14:29:32 WARNING   [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Sending for retry #1 using 922 ms delay. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 1,"delay" => 922,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]
14:29:37 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
14:29:37 WARNING   [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Sending for retry #3 using 3676 ms delay. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 3,"delay" => 3676,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]
14:30:08 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
14:30:08 CRITICAL  [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Removing from transport after 5 retries. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 5,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]
14:30:08 INFO      [messenger] Rejected message AppDomainEventChannelManagerChannelManagerEventHasReceived will be sent to the failure transport SymfonyComponentMessengerBridgeDoctrineTransportDoctrineTransport. ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","transport" => "SymfonyComponentMessengerBridgeDoctrineTransportDoctrineTransport"]

The transports sqs_channel_manager is configured like this:

framework:
    messenger:
        failure_transport: failed
        transports:
            failed: 'doctrine://default?table_name=failed_messages'
            sqs_channel_manager:
              dsn: 'https://sqs.eu-north-1.amazonaws.com/XXXXXX/sqs_channel_manager_test'
              serializer: AppInfrastructureMessengerChannelManagerSerializer
              options:
                  access_key: '%env(AWS_ACCESS_KEY_ID)%'
                  secret_key: '%env(AWS_SECRET_ACCESS_KEY)%'
                  region: '%env(AWS_REGION)%'
                  queue_name: '%env(CHANNEL_MANAGER_QUEUE_NAME)%'

And is an SQS queue The queue has a redrive policy:

aws sqs get-queue-attributes --queue-url https://sqs.eu-north-1.amazonaws.com/XXXXXX/sqs_channel_manager_test --attribute-names RedrivePolicy
{
    "Attributes": {
        "RedrivePolicy": "{"deadLetterTargetArn":"arn:aws:sqs:eu-north-1:XXXXX:sqs_channel_manager_test_dlq","maxReceiveCount":1}"
    }
}

But upon failure message is not placed upon Deal letter queue:

aws sqs get-queue-attributes --queue-url https://sqs.eu-north-1.amazonaws.com/XXXXXXXX/sqs_channel_manager_test_dlq  --attribute-names ApproximateNumberOfMessages
{
    "Attributes": {
        "ApproximateNumberOfMessages": "0"
    }
}

Does failure_transport prevents the message to be placed upon DLQ? Setting failure_transport has no effect:

            sqs_channel_manager:
              failure_transport: null
              dsn: '%env(SQS_CHANNEL_MANAGER_TRANSPORT_DSN)%'
              serializer: AppInfrastructureMessengerChannelManagerSerializer
              options:
                  access_key: '%env(AWS_ACCESS_KEY_ID)%'
                  secret_key: '%env(AWS_SECRET_ACCESS_KEY)%'
                  region: '%env(AWS_REGION)%'
                  queue_name: '%env(CHANNEL_MANAGER_QUEUE_NAME)%'

Also I am using custom serializer:

<?php
declare(strict_types=1);

namespace AppInfrastructureMessenger;

use AppDomainEventChannelManagerChannelManagerEventHasReceived;
use SymfonyComponentMessengerEnvelope;
use SymfonyComponentMessengerStampRedeliveryStamp;
use SymfonyComponentMessengerStampTransportMessageIdStamp;
use SymfonyComponentMessengerTransportSerializationSerializerInterface;

class ChannelManagerSerializer implements SerializerInterface
{
    public function decode(array $encodedEnvelope): Envelope
    {
        $data = json_decode($encodedEnvelope['body'], true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new InvalidArgumentException(
                'Invalid JSON received from SQS: ' . json_last_error_msg()
            );
        }

        $envelope = new Envelope(new ChannelManagerEventHasReceived($data));

        if (isset($encodedEnvelope['headers']['stamps'])) {
            $stamps = unserialize(base64_decode($encodedEnvelope['headers']['stamps']));
            foreach ($stamps as $stamp) {
                $envelope = $envelope->with($stamp);
            }
        }

        return $envelope;
    }

    public function encode(Envelope $envelope): array
    {
        $event = $envelope->getMessage();

        $stampsToSerialize = [];

        foreach ($envelope->all() as $stampArray) {
            foreach ($stampArray as $stamp) {
                if ($stamp instanceof RedeliveryStamp || $stamp instanceof TransportMessageIdStamp) {
                    $stampsToSerialize[] = $stamp;
                }
            }
        }

        return [
            'body' => json_encode($event->channelManagerData, JSON_THROW_ON_ERROR),
            'headers' => [
                'stamps' => base64_encode(serialize($stampsToSerialize)),
            ],
        ];
    }
}

Does it affect a message entering DLQ? I am using Symfony 7.2, it this a known issue?

How to send an S/MIME encrypted file with an empty body using PHPMailer in PHP?

I’m trying to send an email using PHPMailer in PHP that includes an S/MIME encrypted file (smime.p7m) as an attachment. The email should have:
MIME-Version: 1.0
Content-Disposition: attachment; filename=”smime.p7m”
Content-Type: application/x-pkcs7-mime; smime-type=enveloped-data; name=”smime.p7m”
Content-Transfer-Encoding: base64
I want the email body to remain empty (no text/html content). How can I correctly configure PHPMailer to send this type of email with just the encrypted attachment?

I’ve tried using addAttachment() and setting $mail->Body = ”
Any guidance or examples would be appreciated.

My RUN and DEBUG doesn’t appear in vs code Help, I use xampp

I think there was supposed to be a green arrow that says run n rebug but mind just didnt exist, or maybe someone can teach me how to debug in php with xampp

I have PHP DEBUG by xdebug.org installed
I followed this video, https://www.youtube.com/watch?v=8ka_Efpl21Y

I ran my xampp, put a break point in a function where the code is supposed to run,

I open my website by typing the localhost url in chrome,

fill in my form, the website works, but nothing happens from breakpoint.

I saw people on YouTube have something called a run n debug but mine just doesn’t appear. When I press ctrl + shift + D, there’s checkbox for NOTICES, WARNINGS, ERRORS, EXCEPTIONS, EVERYTHING, but green arrow button with run n debug like I saw on YouTube

Why retry cound does not increase upon exception thrown?

In Symfony I use a custom Serializer upon a transport:

framework:
    messenger:
        transports:
            async: '%env(MESSENGER_TRANSPORT_DSN)%'
            failed: 'doctrine://default?table_name=failed_messages'
            sqs_channel_manager:
              dsn: '%env(SQS_CHANNEL_MANAGER_TRANSPORT_DSN)%'
              serializer: AppInfrastructureMessengerChannelManagerSerializer
              options:
                  access_key: '%env(AWS_ACCESS_KEY_ID)%'
                  secret_key: '%env(AWS_SECRET_ACCESS_KEY)%'
                  region: '%env(AWS_REGION)%'
                  queue_name: '%env(CHANNEL_MANAGER_QUEUE_NAME)%'
        failure_transport: failed
        default_bus: command.bus
        buses:
            event.bus: ~
        routing:

I also made this Serializer:


declare(strict_types=1);

namespace AppInfrastructureMessenger;

use AppDomainEventChannelManagerChannelManagerEventHasReceived;
use SymfonyComponentMessengerEnvelope;
use SymfonyComponentMessengerStampBusNameStamp;
use SymfonyComponentMessengerTransportSerializationSerializerInterface;

class ChannelManagerSerializer implements SerializerInterface
{
    public function decode(array $encodedEnvelope): Envelope
    {
        $data = json_decode($encodedEnvelope['body'], true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new InvalidArgumentException(
                'Invalid JSON received from SQS: ' . json_last_error_msg()
            );
        }

        return (new Envelope(new ChannelManagerEventHasReceived($data)))
            ->with(new BusNameStamp('event.bus'));
    }

    public function encode(Envelope $envelope): array
    {
        $event = $envelope->getMessage();

        return [
            'body' => json_encode($event->channelManagerData, JSON_THROW_ON_ERROR),
        ];
    }
}

Then I made this handler emulating an error:

declare(strict_types=1);

namespace AppApplicationEventListener;

use AppDomainEventChannelManagerChannelManagerEventHasReceived;
use Exception;
use SymfonyComponentMessengerAttributeAsMessageHandler;

class ChannelManagerSubscriber extends BaseEventListener
{
    #[AsMessageHandler]
    public function onChannelManagerEvent(ChannelManagerEventHasReceived $event): void
    {
        throw new Exception();
        dump($event);
    }
}

But running the queue:

 php -d memory_limit=-1 bin/console messenger:consume sqs_channel_manager -vv

Does not increase the count:

12:01:20 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
12:01:20 WARNING   [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Sending for retry #1 using 930 ms delay. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 1,"delay" => 930,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]
12:01:21 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
12:01:21 WARNING   [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Sending for retry #1 using 1005 ms delay. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 1,"delay" => 1005,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]
12:01:24 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
12:01:24 WARNING   [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Sending for retry #1 using 983 ms delay. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 1,"delay" => 983,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]
12:01:26 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
12:01:26 WARNING   [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Sending for retry #1 using 929 ms delay. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 1,"delay" => 929,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]
12:01:27 INFO      [messenger] Received message AppDomainEventChannelManagerChannelManagerEventHasReceived ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived"]
12:01:27 WARNING   [messenger] Error thrown while handling message AppDomainEventChannelManagerChannelManagerEventHasReceived. Sending for retry #1 using 1023 ms delay. Error: "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: " ["class" => "AppDomainEventChannelManagerChannelManagerEventHasReceived","message_id" => null,"retryCount" => 1,"delay" => 1023,"error" => "Handling "AppDomainEventChannelManagerChannelManagerEventHasReceived" failed: ","exception" => SymfonyComponentMessengerExceptionHandlerFailedException^ { …}]

As you can see the failure causes "retryCount" => 1 and not be increased. Do you know why?

Displaying about to expire items

I’m displaying Expired Items using this (codeigniter 3)

$qs6="SELECT a.item_name,a.item_code,b.category_name,a.expire_date from db_items as a,db_category as b where b.id=a.category_id and a.expire_date<='".date("Y-m-d")."' and a.status=1 limit 10";
$q6=$this->db->query($qs6);

if($q6->num_rows()>0){
  $i=1;
  foreach ($q6->result() as $row){
    echo "<tr>";
    echo "<td>".$i++."</td>";
    echo "<td>".$row->item_name."</td>";
    echo "<td>".$row->category_name."</td>";
    echo "<td>".show_date($row->expire_date)."</td>";
    echo "</tr>";
  }
}

I want to display another table showing about to expire items 4 months before expiry. How should i display it. Please Help.

setting up wordpress on an amazon linux 2023 ec2 instance [closed]

i have setup the LAMP stack and downloaded wordpress. also, extracted the file, changed wp-config-sample.php to wp-config.php and alreadey placed wordpress in /var/www/html/ folder. buti am only gettong “Apache is working” when paste the ip of my instamce on the web browser.

ive tried to restart httpd but i’m not getting wordpress website

How to make dependency injection lazy and simple using property hooks in php

The problem is to use many objects in constructor but in way that only while path of script goes to one of the condition, then the service will be really created (initialised). I my opinion it is very valuable thing because sometimes one service can throw only the exception according do given data but all dependencies had to be set while constructing which is a big waste of resources.
So how to accomplished it using php?

Server Error The booking service is currently unavailable. Please try again later or contact support [closed]

The main purpose of the code below is for a booking session. Each time I click on the book a session button on the pop-up modal window I get Server Error The booking service is currently unavailable. Please try again later or contact support.

–booking.php–

<?php
// booking.php
require_once 'config.php';

use PHPMailerPHPMailerPHPMailer;
use PHPMailerPHPMailerException;

require __DIR__ . '/../assets/vendor/autoload.php';

header('Content-Type: application/json; charset=UTF-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, X-Requested-With');
header('Access-Control-Allow-Credentials: true');

// Handle preflight OPTIONS
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {

    http_response_code(200);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(["status" => "error", "message" => "Invalid request method"]);
    exit;
}

// Parse JSON
$raw = file_get_contents("php://input");
$input = json_decode($raw, true);

if (!$input) {
    echo json_encode([
        "status" => "error",
        "message" => "Invalid or empty JSON",
        "debug" => (APP_ENV === 'development' ? $raw : null)
    ]);

    exit;
}

// Required fields
$required = ['full_name', 'email', 'phone', 'subject', 'session_type', 'date', 'time', 'details'];

foreach ($required as $field) {

    if (empty($input[$field])) {
        echo json_encode([
            "status" => "error",
            "message" => "Missing required field: $field",
            "debug" => (APP_ENV === 'development' ? $input : null)
        ]);

        exit;
    }
}

// Core fields
$full_name = trim($input['full_name']);
$email = filter_var($input['email'], FILTER_VALIDATE_EMAIL);
$phone = trim($input['phone']);
$subject = trim($input['subject']);
$session_type = trim($input['session_type']);

$date = $input['date'];
$time = $input['time'];
$details = trim($input['details']);
$role = $input['role'] ?? null;

if (!$email) {
    echo json_encode(["status" => "error", "message" => "Invalid email address"]);
    exit;
}

// Optional fields (set null if missing)
$optionalFields = [
'current_challenges','personal_goals','group_size','group_type','group_objectives',
'institution_type','institution_name','educational_goals','org_size','org_sector',
'dev_focus','leadership_level','leadership_challenges','dev_areas','transformation_scope',
'current_state','desired_outcome','timeline'
];


foreach ($optionalFields as $field) {
    $$field = $input[$field] ?? null;
}

try {
    // Save booking
    $stmt = $pdo->prepare("INSERT INTO bookings 
   (full_name,email,phone,subject,session_type,date,time,details,role,
current_challenges,personal_goals,group_size,group_type,group_objectives,
         institution_type,institution_name,educational_goals,
         org_size,org_sector,dev_focus,
         leadership_level,leadership_challenges,dev_areas,
         transformation_scope,current_state,desired_outcome,timeline)
        VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");

    $stmt->execute([
        $full_name, $email, $phone, $subject, $session_type, $date, $time, $details, $role,
$current_challenges,$personal_goals,$group_size,$group_type,$group_objectives,
        $institution_type,$institution_name,$educational_goals,
        $org_size,$org_sector,$dev_focus,
        $leadership_level,$leadership_challenges,$dev_areas,
        $transformation_scope,$current_state,$desired_outcome,$timeline
    ]);

    $booking_id = $pdo->lastInsertId();

    // Send Admin Email
    try {
        $mail = new PHPMailer(true);
        $mail->isSMTP();
        $mail->Host = 'smtp.gmail.com';
        $mail->SMTPAuth = true;
        $mail->Username = MAIL_FROM;
        $mail->Password = MAIL_PASS;
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
        $mail->Port = 587;
        $mail->setFrom(MAIL_FROM, 'Booking System');
        $mail->addAddress(MAIL_TO);
        $mail->isHTML(true);
        $mail->Subject = "New Booking (#$booking_id): $session_type by $full_name";

        $mail->Body = "
            <h2>New Booking Received</h2>
            <p><strong>Name:</strong> $full_name</p>
            <p><strong>Email:</strong> $email</p>
            <p><strong>Phone:</strong> $phone</p>
            <p><strong>Subject:</strong> $subject</p>
            <p><strong>Session:</strong> $session_type</p>
            <p><strong>Date:</strong> $date</p>
            <p><strong>Time:</strong> $time</p>
            <p><strong>Details:</strong><br>" . nl2br($details) . "</p>";
        $mail->send();

    } catch (Exception $e) {
        error_log("Email Error (Admin): " . $e->getMessage());
        echo json_encode(["status"=>"error","message"=>"Email error (admin)","debug"=>(APP_ENV==='development'?$e->getMessage():null)]);
        exit;
    }

    // Send Customer Confirmation
    try {
        $mail = new PHPMailer(true);
        $mail->isSMTP();
        $mail->Host = 'smtp.gmail.com';
        $mail->SMTPAuth = true;
        $mail->Username = MAIL_FROM;
        $mail->Password = MAIL_PASS;
        $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
        $mail->Port = 587;

        $mail->setFrom(MAIL_FROM, '360 Sages');
        $mail->addAddress($email);
        $mail->isHTML(true);
        $mail->Subject = "Booking Confirmation - $session_type";
        $mail->Body = "
            <h2>Hello $full_name,</h2>
            <p>Thank you for booking a <strong>$session_type</strong> session with us.</p>
            <p><strong>Date:</strong> $date</p>
            <p><strong>Time:</strong> $time</p>
            <p>We’ll contact you soon with further details.</p>
            <br>
            <p>Best regards,<br>360 Sages Team</p>";

        $mail->send();
    } catch (Exception $e) {
        error_log("Email Error (Customer): " . $e->getMessage());
        echo json_encode(["status"=>"error","message"=>"Email error (customer)","debug"=>(APP_ENV==='development'?$e->getMessage():null)]);
        exit;
    }

    echo json_encode(["status"=>"success","message"=>"Booking submitted successfully!"]);

} catch (PDOException $e) {
    error_log("Database Error: " . $e->getMessage());
    echo json_encode([
        "status" => "error",
        "message" => "Database error while saving booking",
        "debug" => (APP_ENV === 'development' ? $e->getMessage() : null)
    ]);

    exit;
}

--script.js--
document.addEventListener("DOMContentLoaded", function () {
  const bookingForm = document.getElementById("bookingForm");
  const sessionTypeSelect = document.getElementById("session_type");

  // Inject CSS for shake + label highlight + SweetAlert error color + success glow

  if (!document.getElementById("error-style")) {
    const style = document.createElement("style");
    style.id = "error-style";
    style.textContent = `

      .field-error {
        border: 2px solid red !important;
        animation: shake 0.3s ease-in-out;
      }

      .label-error {
        color: red !important;
        font-weight: bold;
      }

      .form-success {
        animation: glowSuccess 1s ease-in-out;
      }

      .swal2-popup.swal2-toast .swal2-title,
      .swal2-popup .swal2-title,
      .swal2-popup .swal2-html-container {
        color: red !important;
      }

      @keyframes shake {
        0% { transform: translateX(0); }
        25% { transform: translateX(-5px); }
        50% { transform: translateX(5px); }
        75% { transform: translateX(-5px); }
        100% { transform: translateX(0); }
      }

      @keyframes glowSuccess {
        0% { box-shadow: 0 0 0px rgba(0,255,0,0); }
        50% { box-shadow: 0 0 15px rgba(0,255,0,0.7); }
        100% { box-shadow: 0 0 0px rgba(0,255,0,0); }
      }
    `;

    document.head.appendChild(style);
  }

  if (bookingForm) {
    bookingForm.addEventListener("submit", async (e) => {
      e.preventDefault();
      const formDataObj = {};
      const invalidFields = [];

      function getFieldLabel(el) {
        const label = bookingForm.querySelector(`label[for="${el.id}"]`);
        return label ? label.textContent.trim() : el.name.replace("_", " ");
      }

      bookingForm.querySelectorAll("input, textarea, select").forEach((el) => {

        if (el.name) {
          const value = el.value.trim();
          formDataObj[el.name] = value;
          const label = bookingForm.querySelector(`label[for="${el.id}"]`);

          if (label) label.classList.remove("label-error");

          el.classList.remove("field-error");

          if (el.hasAttribute("required") && !value) {

            invalidFields.push({ field: el, message: `${getFieldLabel(el)} is required.` });
          }

          if (el.type === "email" && value) {
            const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;

            if (!emailRegex.test(value)) {
              invalidFields.push({ field: el, message: `Please enter a valid ${getFieldLabel(el)}.` });
            }
          }

          if (el.type === "tel" && value) {
            const phoneDigits = value.replace(/D/g, "");

            if (phoneDigits.length < 7) {
              invalidFields.push({ field: el, message: `${getFieldLabel(el)} must have at least 7 digits.` });
            }
          }
        }
      });

      formDataObj.session_type = sessionTypeSelect.value;

      for (const invalid of invalidFields) {
        const field = invalid.field;
        const label = bookingForm.querySelector(`label[for="${field.id}"]`);

        field.classList.add("field-error");

        if (label) label.classList.add("label-error");

        field.scrollIntoView({ behavior: "smooth", block: "center" });

        await Swal.fire({
          icon: "error",
          title: "Invalid Field",
          html: `<span style="color:red; font-weight:bold;">⚠️ ${invalid.message}</span>`,
          confirmButtonColor: "#152942",
          didClose: () => {
            field.focus();
            field.classList.remove("field-error");

            if (label) label.classList.remove("label-error");
          },
        });
      }

      if (invalidFields.length > 0) return;

      Swal.fire({
        title: "Submitting...",
        text: "Please wait while we process your booking.",
        allowOutsideClick: false,
        didOpen: () => Swal.showLoading(),
      });

      try {
        const apiUrl = new URL(
          "includes/booking.php",
          window.location.origin + window.location.pathname
        ).href;

        const response = await fetch(apiUrl, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(formDataObj),
        });

        const result = await response.json();

        if (result.status === "success") {
          window.scrollTo({ top: 0, behavior: "smooth" });

          // Add subtle green glow animation
          bookingForm.classList.add("form-success");
          setTimeout(() => bookingForm.classList.remove("form-success"), 1000);


          Swal.fire({
            icon: "success",
            title: "Booking Confirmed",
            text: result.message,
            confirmButtonColor: "#152942",
          });

          bookingForm.reset();

          if (typeof closeModal === "function") closeModal();

        } else {
          let errorMsg = "Booking failed. Please try again.";

          if (result.message.includes("Database")) errorMsg = "Database Error: Unable to save your booking.";

          else if (result.message.includes("Email error (admin)")) errorMsg = "Email Error: Failed to notify admin.";

          else if (result.message.includes("Email error (customer)")) errorMsg = "Email Error: Failed to send confirmation to your email.";

          Swal.fire({
            icon: "error",
            title: "Error",
            html: `<span style="color:red; font-weight:bold;">${errorMsg}</span>`,
            confirmButtonColor: "#152942",
          });

          if (result.debug) console.error("Debug Info:", result.debug);
        }
      } catch (error) {
        console.error("Error:", error);

        Swal.fire({
          icon: "error",
          title: "Server Error",
          html: `<span style="color:red; font-weight:bold;">⚠️ The booking service is unavailable.</span>`,
          confirmButtonColor: "#152942",
        });
      }
    });
  }
}
);

Laravel Polymorphic Relations And Has Many Through

Tried to find a solution, but couldn’t find a similar problem.
I have two classes: Product and TempProduct. Both inherit from BaseProduct.
BaseProduct doesn’t have a table name defined, but Product and TempProduct do.

I also have an Order model that has the following relation:

public function products()
    {
        return $this->morphTo('products', 'product_type', 'product_id');
    }

The product_type column is an enum with values “product” or “product_temp” to indicate which table the product comes from.

Then I have a Shop model that is connected to Order:

public function shop_order()
    {
        return $this->hasMany(Order::class, 'order_id', 'id')->withTrashed();
    }

Previously, before adding TempProduct, I used the following hasManyThrough relation:

public function products_sell()
    {
        return $this->hasManyThrough(Product::class, Order::class, 'order_id', 'id', 'id', 'product_id');
    }

Now that I’ve added TempProduct and switched to a polymorphic relation, I’m not sure how to implement hasManyThrough in this case.

ERR_TOO_MANY_REDIRECTS htaccess issue?

I have a site on a VPS. It’s a combination of static html and a WMPU installation, where I use subsites for categories.

I was working on migrating all static html content to WP pages, and decided to use the main WP of WPMU for this (so pages would have the following url structure: www.tmpdomain.com/this-is-a-page).

It all worked ok until I had to switch VPS recently. I adjusted DNS at my registrar/host and also altered the Cloudflare settings so it would all point to the new IP address.

However, everything works fine except for the pages that I made within the main WP. Those now are not working and show a ERR_TOO_MANY_REDIRECTS.

Besides the htaccess code provided through WPMU, the following code was added a long time ago to make sure the static html is shown first (as home/landing page) and not the index.php of the WPMU main part:

Options +FollowSymLinks
RewriteEngine On
RewriteCond %{HTTP_HOST} ^tmpdomain.com [NC]
RewriteRule ^(.*)$ https://www.tmpdomain.com/$1 [R=301,L]
RewriteRule ^(.*)RK=0/RS= /$1 [L,NC,R=301]
RewriteRule ^(.*)RS=^ /$1 [L,NC,R=301]

I am not sure what causes that error/loop. As far as I know nothing changed besides the IP (and VPS itself).

To specify what works and what not:

This works:

www.tmpdomain.com
www.tmpdomain.com/this-is-a-page.htm
www.tmpdomain.com/subsite/this-is-a-page (wordpress MU subsite page)

This does not work:

www.tmpdomain.com/this-is-a-page (wordpress MU main page)

Can anyone perhaps verify if the code in my htaccess should work with the goal of serving the index.htm instead of index.php and do people perhaps have a clue where to start looking for the strange endless redirect on the WordPress pages (only the ones in the main category of WPMU, not the subsites)?

I removed the htaccess part I showed above. Site works with no difference. Issue remains.

I checked all places where I can adjust the IP. It is correct.

I turned off all plugins, turned them on one by one. No change.

I might need to look into the database, but not sure where to start.

Doctrine Translatable: Is it possible to override the ID generation strategy of AbstractPersonalTranslation?

I need some help regarding the usage of Doctrine Translatable (from Doctrine Extensions)

Context

I use Doctrine Translatable to translate an entity, and my use-case follows closely this example from the docs.

This approach, where the translation entity extends AbstractPersonalTranslation, leads to a translation table having an ID generation with strategy “IDENTITY”, because AbstractPersonalTranslation is as follows:

...
#[ORMMappedSuperclass]
abstract class AbstractPersonalTranslation
{
    #[ORMColumn(type: Types::INTEGER)]
    #[ORMId]
    #[ORMGeneratedValue(strategy: 'IDENTITY')]
    protected $id;
...

The issue

The fact is that, for reasons that I explain at the end of the post, I want to change the definition of the GeneratedValue strategy for my translation table extending AbstractPersonalTranslation.

What I have tried

I tried overriding the property as follows in my child class:

class MyEntityTranslation extends AbstractPersonalTranslation
{
    #[ORMColumn(type: Types::INTEGER)]
    #[ORMId]
    #[ORMGeneratedValue(strategy: 'SEQUENCE')]
    protected $id;
...

however I get the following error:

In MappingException.php line 420:
                                                                                                                                                    
  Duplicate definition of column 'id' on entity 'AppEntityTranslationDeviceNotificationTranslation' in a field or discriminator column mapping.

Why do I want to do this?

This is probably not relevant for the issue but the reason why I need to change the auto-generated ID strategy is because I am currently upgrading my project ot Doctrine’s ORM 3 and DBAL 4 with a PostgreSQL DB, which changes the default strategy. I would like to deploy the upgrade without changing my DB tables and, afterwards, perform the migration of the DB IDs (as suggested by some important contributors)

Shortcode is print blank info

I’m using WordPress (WooCommerce) with the Eventon plugin.
I’m trying to print the event location and event date in the WordPress email template.

Here is the code that I’m using:

if ( isset($attr['type']) && $attr['type'] == 'event-date' ) {
    foreach ( $order->get_items() as $item_id => $item ) {
        $event_id = $item->get_product_id();
        $event_date = get_post_meta( $event_id, '_EventStartDate', true );

        if ( ! empty( $event_date ) ) {
            // Format event date
            $formatted_date = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $event_date ) );
            printf( __( "%s", 'wc-pre-orders' ), '<b>' . esc_html( $formatted_date ) . '</b>' );
        }
    }
}

// Event Location
if ( isset($attr['type']) && $attr['type'] == 'event-location' ) {
    foreach ( $order->get_items() as $item_id => $item ) {
        $event_id = $item->get_product_id();
        $venue_id = get_post_meta( $event_id, '_EventVenueID', true );

        if ( $venue_id ) {
            $venue_name = get_the_title( $venue_id );
            $venue_address = get_post_meta( $venue_id, '_VenueAddress', true );

            printf(
            __( "%s", 'wc-pre-orders' ),
            '<b>' . esc_html( $venue_name . ( $venue_address ? ' - ' . $venue_address : '' ) ) . '</b>'
            );
        }
    }
}

Do you have any idea why it doesn’t print the information? (event location + event date)

Custom document root in XAMPP

I’m currently going through Laracast’s PHP for Beginners series, and in episode 30, they make a change to the document root. I’m using XAMPP on Windows, and the default document root in my httpd.conf was C:/xampp/htdocs. I’ve changed this to my desired document root, C:/xampp/htdocs/public, but only the public/index.php page works and nothing else.

I seem to receive a 404 when trying to access any file/page that’s outside the /public folder, which makes sense. However, they watching the video, they seem to be able to.

https://www.youtube.com/watch?v=cayyhoFnqSY&list=PL3VM-unCzF8ipG50KDjnzhugceoSG3RTC&index=30

My file structure is as follows:

controllers
    notes
        create.php
        index.php
    index.php
public
    index.php
views
    notes
        create.view.php
        index.view.php
    partials
        banner.php
        footer.php
        header.php
        nav.php
    404.php
    index.view.php
config.php
Database.php
functions.php
router.php
routes.php
Validator.php

My current httpd.conf (Line 252 & 253):

DocumentRoot "C:/xampp/htdocs/public"
<Directory "C:/xampp/htdocs/public">

I’ve also tried the following in httpd-vhosts.conf instead (https://serverfault.com/questions/917029/apache-server-wont-change-root-directory):

<VirtualHost *:80>
    ServerAdmin [email protected]
    DocumentRoot "C:/xampp/htdocs/public"
    ServerName localhost
    <Directory "C:/xampp/htdocs/public">
        Options Indexes FollowSymLinks Includes ExecCGI
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

My .htaccess file (tried commenting these rules out, in case they caused issues):

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]

My router.php file:

$uri = parse_url($_SERVER['REQUEST_URI'])['path'];

$routes = [
    '/' => 'controllers/index.php',
    '/notes' => 'controllers/notes/index.php',
    '/notes/create' => 'controllers/notes/create.php',
];

function routeToController($uri, $routes) {
    if (array_key_exists($uri, $routes)) {
        require $routes[$uri];
    } else {
        abort();
    }
}