How to fork and maintain a WooCommerce Block separately?

WooCommerce offers a Gutenberg block called “Products By Category”. We make use multiple instances of this on our site’s landing page. With the help of the Query Monitor plugin, we noticed that the DB Queries was too high. Once we removed some or all the instance of this block, the DB queries came down by a lot (from ~550 to ~80).

After taking a look at it’s source, I noticed that it only caches the exact IDs to be resolved. The product details though have to be fetched everytime from the DB. Therefore, I modified render method to simply cache the final HTML output and show that instead. This drastically reduced DB queries as expected.

Ideally, I would like to modify the behaviour by writing a custom plugin/theme. Unfortunately, so far I haven’t found a proper solution to this yet. WC Blocks seem to be tightly integrated, with internal dependencies. It seems like there used to be a way to package the blocks separately as their own plugin, but it seems to be removed and no longer supported.

Currently, I am doing the following to get it working, but involves using reflection and thus I would like to avoid:

  1. Use JS gutenberg filter to get current declared render_callback, store reference to the object.

  2. Use PHP ReflectionClass to modify/access properties within the object. use them in my custom render function.

  3. Use JS gutenberg filter to change render_callback to my custom function.

PHP8.3 got stuck until previous request was finished

I’ve nginx + php-fpm(PHP8.3) installed on my Windows PC’s Docker Container(based on Ubuntu 24.04 amd64 image). and I have the following sample script test.php:

<?php
//exit(0);
sleep(60);

First, run this PHP script in the browser, this request will hang about 60 sec to simulate very long PHP executions. Then, before the previous page execution is fully finished, I removed the comment before exit(0), and fire another HTTP request via browser, but it seems the second request must waiting for the previous request finishing to start processing, why?

Here is the PHP-FPM Status Page result from nginx+php-fpm in my docker container:

(There is only one test.php in PHP-FPM Status Page while two test.php is still loading in browser, WHY?)

pid:                  25
state:                Running
start time:           15/Dec/2024:13:17:39 +0800
start since:          4242
requests:             21
request duration:     10050015
request method:       GET
request URI:          /test.php
content length:       0
user:                 -
script:               /var/www/html/test.php
last request cpu:     0.00
last request memory:  0

P.S.1. I’ve tried the solution at PHP Page Stuck at Loading while Another PHP script is running, but not worked for me..

P.S.2 Also tried Show results while script is still executing, still not worked for me

P.S.3 I also tried install the following software to my docker container: apache2+php8.3/apache2+php8.3-fpm/nginx+php8.3-fpm, and tried install Laragon to run nginx+php 8.1 directly in my Windows PC. the issue still reproducable.

EDIT:

Here is the reproducible test steps:

Step 1. Access the script provided above from the browser.
Step 2. While previous script is still running, uncomment the code `//exit(0);` at line 2
Step 3. Open a new brower tab. Access the same script again.

You will see the Step 3 will load for a huge time until the running script from Step 1 is done.

I’ve confirmed that no (file-based) session is started/created during script running by checking session.auto_start at runtime (it outputs 0) and checking variable isset($_SESSION) (Result: false)

PHP when running a “foreach”, find out which item on the list was a match [duplicate]

When this code is run, how can I echo matched variable from $spam_keywords?

Once a variable is matched/found I would like echo it or save it to another veriable.

$uri = $_SERVER['REQUEST_URI'];

$spam_keywords = [
    'spamword1',
    'spamword2',
    'spamword3'
// WILL BE A LOT MORE HERE
];

function checkKeywords($uri, $keywords) {
    foreach ($keywords as $keyword) {
        if (strpos($uri, $keyword) !== false) {
            return true;
        }
    }
    return false;
}

if (checkKeywords($uri, $spam_keywords)) {
    // HERE I NEED TO ECHO WHICH KEYWORD WAS MATCHED
    echo "<p>HOW TO ECHO WHICH KEYWORD WAS MATCHED?</p>";
} else {
    echo "keywords not found";
}

4th answer of account recovery security questions always coming back wrong

I have made a login page and at the end of signing up you have to fill out a few questions for if you ever forget your password. 3 of the questions are already done and you only need to choose a answer but the 4th question has a customizable question and answer. I have made it so when you put your answers and question gets sent to the database it becomes hashed e.g: $customanswer = password_hash($customanswer_before, PASSWORD_BCRYPT);. when you try to do the “forgot password” the first 3 answers are working fine, they say when its right / wrong but the 4th one will always say its wrong even when i put the right answer.

I cant find anything about answer 4 that is different from the other three and chatgpt keeps telling me to do the same things that i have already done and wont be any help at all.

Here is the trouble shoot chatgpt keeps telling me to check (it wont be much help i don’t think, just says what we already know)

Stored Answer One Hash: $2y$10$CzRs7kB80VXBH8cAyXvo9.WdIyZWMRTg0MDaEPZapUu8KI5nit5NC
Stored Answer Two Hash: $2y$10$O/8Epdwo8e/6mTBznqypwuGtRQ8ODoLDstq1Yqv4RoiYLgC55u6Xq
Stored Answer Three Hash: $2y$10$7P8z0u2g5gm0.iv0bpcQ9evto92KM.D5xCQ8YD0f84ImBTW6U7tLq
Stored Answer Four Hash: $2y$10$Ol6O7nmsjYjAL8yqwP8F3Ob.xCDIFDCHn/MfPFZjWoDn5eTkxzgbe
Entered Answer One: one
Entered Answer Two: two
Entered Answer Three: three
Entered Answer Four: four
Is Answer One Correct? Yes
Is Answer Two Correct? Yes
Is Answer Three Correct? Yes
Is Answer Four Correct? No
One or more answers are incorrect. Please try again.

Question 1, 2 and 3 are working fine only problem is number 4 and i have no clue why, if anyone sees/finds a problem with it please reply my code is below,

Thank You,
Alex.:

index:

<body>
<div class="signup" id="signup">

<form action="answer-check.php" method="post">

    <div class="accountrecoverytitle">
        <b>Account Recovery</b>
    </div>

    <div class="accountrecoverytext">
    We understand that forgetting your password happens to the best of us.<br>
    Please answer the following four security questions to verify your <br>
    identity and reset your password <br>
    </div>


    <div class="questionbox" id="question1"> 
        <div class="question">
            <div id="questiontext">What is the name of the first school you went to?</div>
        </div>
        <div class="answer">
            <input id="textbox" type="textbox" name="answerone" require>
        </div>
    </div>



    <div class="questionbox" id="question2">
        <div class="question">
            <div id="questiontext">What is the name of the street you grew up in?</div>
        </div>
        <div class="answer">
            <input id="textbox" type="textbox" name="answertwo" require>
        </div>
    </div>



    <div class="questionbox" id="question3">
        <div class="question">
            <div id="questiontext">What is the name of your first pet?</div>
        </div>
        <div class="answer">
            <input id="textbox" type="textbox" name="answerthree" require>
        </div>
    </div>



    <div class="questionbox" id="question4">
        <div class="question">
            <div id="questiontext">The custom question (Question 4)</div>
        </div>
        <div class="answer">
            <input id="textbox" type="textbox" name="answerfour" require>
        </div>
    </div>

    <button type='submit' id="check-button" >Check</button>


</form>     
</div>

</body>

answer-check.php:

<?php
session_start();

if ($_SERVER["REQUEST_METHOD"] == "POST") {
    // Get form answers directly (they are in plain text)
    $answerone = $_POST['answerone'];
    $answertwo = $_POST['answertwo'];
    $answerthree = $_POST['answerthree'];
    $answerfour = $_POST['answerfour'];  // Including 4th answer here

    $email = $_SESSION['email']; // Assuming the email is stored in session
    $servername = "localhost";
    $username = "root";
    $password = "";
    $dbname = "test"; // Change to your actual DB

    // Create connection
    $conn = new mysqli($servername, $username, $password, $dbname);
    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    }

    // Prepare the SQL query to get the security question answers (already hashed)
    $sql = "SELECT Answer1, Answer2, Answer3, Answer4 
            FROM accounts 
            WHERE email = '$email'";

    $result = $conn->query($sql);

    if ($result->num_rows > 0) {
        // Fetch user data
        $row = $result->fetch_assoc();
        
        // Debugging output (for viewing data being compared)
        echo "Stored Answer One Hash: " . $row['Answer1'] . "<br>";
        echo "Stored Answer Two Hash: " . $row['Answer2'] . "<br>";
        echo "Stored Answer Three Hash: " . $row['Answer3'] . "<br>";
        echo "Stored Answer Four Hash: " . $row['Answer4'] . "<br>";

        echo "Entered Answer One: " . $answerone . "<br>";
        echo "Entered Answer Two: " . $answertwo . "<br>";
        echo "Entered Answer Three: " . $answerthree . "<br>";
        echo "Entered Answer Four: " . $answerfour . "<br>";

        // Use password_verify to match the plain-text answers with the already hashed stored values
        $is_answer_one_correct = password_verify($answerone, $row['Answer1']);
        $is_answer_two_correct = password_verify($answertwo, $row['Answer2']);
        $is_answer_three_correct = password_verify($answerthree, $row['Answer3']);
        $is_answer_four_correct = password_verify($answerfour, $row['Answer4']);

        // Debug output for verification
        echo "Is Answer One Correct? " . ($is_answer_one_correct ? "Yes" : "No") . "<br>";
        echo "Is Answer Two Correct? " . ($is_answer_two_correct ? "Yes" : "No") . "<br>";
        echo "Is Answer Three Correct? " . ($is_answer_three_correct ? "Yes" : "No") . "<br>";
        echo "Is Answer Four Correct? " . ($is_answer_four_correct ? "Yes" : "No") . "<br>";

        // Checking if all answers are correct
        if ($is_answer_one_correct && $is_answer_two_correct && $is_answer_three_correct && $is_answer_four_correct) {
            // All answers are correct, you can allow the user to reset the password
            echo "All answers are correct. You may now reset your password.";
        } else {
            // One or more answers are incorrect
            echo "One or more answers are incorrect. Please try again.";
        }
    } else {
        // No account found for that email
        echo "No account found for the email provided.";
    }

    // Close the connection
    $conn->close();
}
?>

Code that sends info to database:

<?php

session_start();
//All Variables
//linking html data to php E.G:$phpvariable = $_POST["HTML form NAME"]


//needs hashed
$pass_before = $_POST["password"];
$answerone_before = $_POST["security_question_one"];
$answertwo_before = $_POST["security_question_two"];
$answerthree_before = $_POST["security_question_three"];
$customquestion_before = $_POST["custom_security_question"];
$customanswer_before = $_POST["custom_secruity_answer"];


//doesnt need hashed
$user = $_POST["usernames"];
$email = $_POST["email"];
$firstname = $_POST["firstname"];
$middlename = $_POST["middlename"];
$lastname = $_POST["lastname"];
$date = $_POST["dob"];
$phone = $_POST["phone"];
$address = $_POST["address"];
$gender = $_POST["gender"];

//becomes hashed
$pass = password_hash($pass_before, PASSWORD_BCRYPT);      
$answerone = password_hash($answerone_before, PASSWORD_BCRYPT);
$answertwo = password_hash($answertwo_before, PASSWORD_BCRYPT);
$answerthree = password_hash($answerthree_before, PASSWORD_BCRYPT);
$customquestion = password_hash($customquestion_before, PASSWORD_BCRYPT);
$customanswer = password_hash($customanswer_before, PASSWORD_BCRYPT);


$EmailUserCheck = 0;


$servername = "localhost";
$username = "root";
$password = "";
$dbname = "test";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
}

//check for email taken
$query = "SELECT * FROM accounts WHERE email = '$email'";

// Execute the query 
$result = $conn->query($query); 
 
// Check if the email exists in the database 
if ($result->num_rows > 0) { 
    die("The email: <b>$email</b> is alredy in use 
    <br>
    To fix this you can 
    <b>login</b>
     or 
    <b>contact us</b>
    <br>
    <a href='login.html'><button class='b'>login</button></a>
    <br>
    <a href='contact.html'><button class='b'>contact us</button></a>
    <style>
    .b {
        width: 150px;
        margin-top: 30px;
        height: 30px;
    }
    </style.
    ");
}

// Close the connection 
$conn->close(); 



//reset to send data over
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "test";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
  die("Connection failed: " . $conn->connect_error);
}

$sql = "INSERT INTO accounts (
Username, 
Email,
Password,
First_Name,
Middle_Name,    
Last_name,
Date_Of_Birth,
Phone,
Address,
Gender,
Answer1,    
Answer2,
Answer3,
Question1,
Answer4
)
VALUES (
'$user',
'$email',
'$pass',
'$firstname',
'$middlename',
'$lastname',
'$date',
'$phone',
'$address',
'$gender',
'$answerone',
'$answertwo',
'$answerthree',
'$customquestion',
'$customanswer'
)";

if ($conn->query($sql) === TRUE) {
  header("Location: login.php?signup=complete");
  exit();
} else {
  echo "Error: " . $sql . "<br>" . $conn->error;
}

$conn->close();
?>

File download PHP from MySQL database [duplicate]

if (isset($_GET['file_id'])) {
    $id = $_GET['file_id'];

    // fetch file to download from database
    $sql = "SELECT * FROM files WHERE id=$id";
    $result = mysqli_query($conn, $sql);

    $file = mysqli_fetch_assoc($result);
    $filepath = 'uploads/' . $file['name'];

    if (file_exists($filepath)) {
        header('Content-Description: File Transfer');
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename=' . basename($filepath));
        header('Expires: 0');
        header('Cache-Control: must-revalidate');
        header('Pragma: public');
        header('Content-Length: ' . filesize('uploads/' . $file['name']));
        
        //This part of code prevents files from being corrupted after download
        ob_clean();
        flush();
        
        readfile('uploads/' . $file['name']);

        // Now update downloads count
        $newCount = $file['downloads'] + 1;
        $updateQuery = "UPDATE files SET downloads=$newCount WHERE id=$id";
        mysqli_query($conn, $updateQuery);
        exit;
    }

}

Am getting this error:

Parse error: syntax error, unexpected identifier “file_id”, expecting
“)”

On remote server but on local host is working fine with no errors.
Below is my download code
On the local host is working fine

Cors issue local xampp server and react frontend

I have a local Xampp running on http://localhost (port 80)
This server provides an api in folder kiosk2/api (root file api.php)

The .htaccess file in this folder is

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule !^src($|/) api.php [L]

I have a react app running using vite on localhost:5173

When I fetch an endpoint without adding headers, it works fine

const res = await fetch(`http://localhost/kiosk2/api/items`);

However, when I use another request and try to add an authorization token, I get a cors error.

const rawResponse = await fetch(url, {
    headers: {
      Authorization: "Basic " + btoa(user + ":" + password),
    },
  });

gives the following error in the browser:

Access to fetch at ‘http://localhost/kiosk2/api/login’ from origin ‘http://localhost:5173’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

Can anybody help me out?

Blockcypher Saying Transaction Successful Yet Doesn’t Show Up On Blockchain Explorer

Greetings everyone I am developing an e-commerce site that allows bitcoin transactions. I am trying to allow buyers to purchase products on the site using bitcoin. I have setup a wallet system that detects the amount of bitcoin the user has by scraping the blockchain explorer or blockchain.info. I have a problem though. I am using blockcypher which is an api to allow the processing of bitcoin transactions. I am stumped as to why it is saying order successfully placed and then it gives a transaction ID as confirmation so that the user can track the progress of the transaction on any of the blockchain explorers such as blochain.com or blockcyper. The code has been put through chatgpt and has no errors and it says the order was placed successfully. Huge disclaimer this is just a hobby project I have no intentions of ever taking it live so don’t mind the products. Can anyone here help me with getting the transactions to broadcast and show up properly. Below is the code from checkout.php

<?php
session_start();
require_once("db.php");  // Ensure the database connection is established

// Ensure the user is logged in
if (!isset($_SESSION['username'])) {
    echo "<h1>You must be logged in to view your cart.</h1>";
    exit;
}

// Get the logged-in user's username
$username = $_SESSION['username'];

// Query to get the user's available Bitcoin balance and wallet address from the register table
$queryBalance = "SELECT available_bitcoin_balance, bitcoin_wallet_address FROM register WHERE username = ?";
$stmtBalance = $conn->prepare($queryBalance);
$stmtBalance->bind_param("s", $username);
$stmtBalance->execute();
$resultBalance = $stmtBalance->get_result();

if ($resultBalance->num_rows === 0) {
    echo "<h1 style='text-align:center;'>No Bitcoin balance found for this user.</h1>";
    exit;
}

$rowBalance = $resultBalance->fetch_assoc();
$availableBitcoinBalance = $rowBalance['available_bitcoin_balance'];
$userBitcoinWalletAddress = $rowBalance['bitcoin_wallet_address'];  // Get the user's Bitcoin wallet address

// Fetch the live BTC to USD conversion rate from CoinGecko API
function getBtcToUsdConversionRate() {
    $url = 'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);

    if ($response === false) {
        return 30000;  // Default value in case of an error
    }

    $data = json_decode($response, true);
    return isset($data['bitcoin']['usd']) ? $data['bitcoin']['usd'] : 30000;  // Default to 30000 USD/BTC if not found
}

// Fetch Bitcoin balance from Blockchain API (Blockchain.info)
function getWalletBalance($walletAddress) {
    $url = "https://blockchain.info/rawaddr/$walletAddress";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);

    if ($response === false) {
        return 0; // In case of an error, return 0
    }

    $data = json_decode($response, true);
    if (isset($data['final_balance'])) {
        // Final balance is in satoshis, convert it to BTC (1 BTC = 100,000,000 satoshis)
        return $data['final_balance'] / 100000000;
    }

    return 0; // Return 0 if balance is not found
}

// Query to get cart items for the user
$query = "
    SELECT c.product_id, c.name, c.quantity, c.total_price, c.vendor_bitcoin_wallet_address
    FROM cart c
    WHERE c.username = ?
";
$stmt = $conn->prepare($query);
$stmt->bind_param("s", $username);  // Bind the username parameter securely
$stmt->execute();  // Execute the query
$result = $stmt->get_result();  // Get the result set

// Debugging: check if any rows are returned
if ($result->num_rows === 0) {
    echo "<h1 style='text-align:center;'>Your cart is empty.</h1>";
    exit;
}

$totalCartPrice = 0;

// Display the user's Bitcoin wallet balance above the purchase button
$userWalletBalance = getWalletBalance($userBitcoinWalletAddress);

echo "<h2 style='text-align:center;'>Your Wallet Balance: <b>$userWalletBalance BTC</b></h2>";

echo "<table style='width:60%; border-radius: 20px;'>
        <tbody>
            <tr>
                <td style='border-radius: 20px 20px 0px 0px;' bgcolor='#2f3947'>
                    <center><font color='white'>
                    <i class='fab fa-bitcoin'></i> Bitcoin - Cart</font></center>
                </td>
            </tr>
            <tr><td>
                <table border='0'>
                    <tbody>
                        <tr>
                            <td bgcolor='#D8D8D8' style='width:1%'></td>
                            <td bgcolor='#D8D8D8'><h6><b>Title</b></h6></td>
                            <td bgcolor='#D8D8D8' style='width:15%'><h6><b>Total Price</b></h6></td>
                            <td align='center' bgcolor='#D8D8D8' style='width:10%'><h6><b>Action</b></h6></td>
                        </tr>";

while ($row = $result->fetch_assoc()) {
    $productId = htmlspecialchars($row['product_id']);
    $productName = htmlspecialchars($row['name']);
    $quantity = (int)$row['quantity'];
    $totalPriceItem = number_format(floatval($row['total_price']), 2);
    $vendorBitcoinWalletAddress = htmlspecialchars($row['vendor_bitcoin_wallet_address']);  // Vendor Bitcoin address

    // Add item total price to the cart total price
    $totalCartPrice += floatval($row['total_price']);

    // Convert total USD price to Bitcoin
    $totalCartPriceInBtc = $totalCartPrice / getBtcToUsdConversionRate();

    // Check if user has enough Bitcoin to cover the total price in Bitcoin
    $hasEnoughBitcoin = $userWalletBalance >= $totalCartPriceInBtc;

    // Decide which button to show
    $actionButton = $hasEnoughBitcoin
        ? "<form method='POST'>
                <input type='hidden' name='username' value='$username'>
                <input type='hidden' name='total_price' value='$totalCartPrice'>
                <input type='hidden' name='available_bitcoin_balance' value='$userWalletBalance'>
                <input type='hidden' name='vendor_bitcoin_address' value='$vendorBitcoinWalletAddress'>
                <button class='btn btn-danger' style='border-radius: 50px; padding: 15px 25px; font-size: 18px;' type='submit'>Purchase</button>
            </form>"
        : "<button class='btn btn-outline-secondary btn-xs' type='button'>-</button>";

    // Display the cart item
    echo "<tr>
            <td><center>
                <a href='cart.php?remove_id=$productId'> <font color='#4a536e'><i class='fas fa-trash'></i> Delete</font></a>
            </center></td>
            <td valign='top'>
                <a href='product.php?id=$productId'>$productName</a><br>
                $quantity x | <a href='product.php?id=$productId'>
                    <font color='#4a536e'> $productName</font></a><br>
                <h6><i>Priority Mail - <b><font color='#007bff'>USD $totalPriceItem</font></b></i> | 
                <button class='escrow2 button3'>&nbsp;&nbsp;&nbsp;&nbsp; Escrow &nbsp;&nbsp;&nbsp;&nbsp;</button></h6>
            </td>
            <td align='center'>
                <h6><b><font color='#007bff'>USD $totalPriceItem</font></b></h6>
            </td>
            <td>
                <center>
                    $actionButton
                </center>
            </td>
        </tr>";
}

echo "    </table>
        </tbody>
    </table>";

// Process the payment after the "Purchase" button is clicked
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Check if POST keys exist before accessing them
    if (isset($_POST['username'], $_POST['total_price'], $_POST['available_bitcoin_balance'], $_POST['vendor_bitcoin_address'])) {
        // Fetch data from POST request
        $username = $_POST['username'];
        $totalPrice = $_POST['total_price'];
        $availableBitcoinBalance = $_POST['available_bitcoin_balance'];
        $vendorBitcoinWalletAddress = $_POST['vendor_bitcoin_address'];

        // Fetch the live BTC to USD conversion rate
        $btcToUsdConversionRate = getBtcToUsdConversionRate();

        // Convert the total price to Bitcoin
        $totalCartPriceInBtc = $totalPrice / $btcToUsdConversionRate;

        // Set the fixed miner fee in USD
        $minerFeeUsd = 3.00;
        $minerFeeBtc = $minerFeeUsd / $btcToUsdConversionRate;

        // Add miner fee to the total price in Bitcoin
        $totalAmountInBtc = $totalCartPriceInBtc + $minerFeeBtc;

        // Check if user has enough Bitcoin to cover the total price + fee
        if ($availableBitcoinBalance < $totalAmountInBtc) {
            echo "<h1 style='text-align:center;'>Insufficient Bitcoin balance</h1>";
            exit;
        }

        // BlockCypher Transaction Creation
        $blockCypherToken = '6fcd4a8a0a4a4bf383b8da45f1f84410';  // Replace with your BlockCypher API token
        $buyerPrivateKey = 'L1JeSdynCTX8LwYcp2VUL8dxY1BSmGBwfUqTsYpuyZH8Mf8FDLUo';  // Replace with the buyer's private key
        $sellerPrivateKey = 'L4YqKJYjFRBnHZoQDMWi1ugimGqsaHW2LyqDvzrV8V2f1h4p6FGU';  // Replace with the seller's private key

        // Create the transaction data with two inputs
        $txData = [
            'inputs' => [
                ['addresses' => [$userBitcoinWalletAddress]],  // Buyer address
                ['addresses' => [$vendorBitcoinWalletAddress]], // Seller address
            ],
            'outputs' => [
                ['addresses' => [$vendorBitcoinWalletAddress], 'value' => (int)($totalCartPriceInBtc * 100000000)],  // Amount to the seller in satoshis
                ['addresses' => [$userBitcoinWalletAddress], 'value' => (int)($minerFeeBtc * 100000000)], // Miner fee to the buyer's address
            ],
        ];

        // Step 1: Create the transaction with BlockCypher
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 'https://api.blockcypher.com/v1/btc/main/txs/new?token=' . $blockCypherToken);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($txData));
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
        $response = curl_exec($ch);
        curl_close($ch);

        // Handle the BlockCypher response and sign the transaction
        $txResponse = json_decode($response, true);

        if (isset($txResponse['tx']['hash'])) {
            $unsignedTx = $txResponse['tx'];

            // Sign the transaction with both private keys (buyer & seller)
            $signData = [
                'tx' => $unsignedTx,
                'signatures' => [
                    $buyerPrivateKey,  // Sign with buyer's private key for the first input
                    $sellerPrivateKey, // Sign with seller's private key for the second input
                ],
            ];

            // Step 2: Send the signed transaction
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, 'https://api.blockcypher.com/v1/btc/main/txs/send?token=' . $blockCypherToken);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($signData));
            curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
            $signedResponse = curl_exec($ch);
            curl_close($ch);

            $signedTxResponse = json_decode($signedResponse, true);

            if (isset($signedTxResponse['tx']['hash'])) {
                // Broadcasted transaction hash
                $txid = $signedTxResponse['tx']['hash'];

                // Show the success message
                echo "<h1 style='text-align:center;'>Order placed successfully!</h1>";
                echo "<p>Transaction ID: $txid</p>";
                echo "<p>Transaction Hash: $txid</p>";

                // Optionally, update the user's Bitcoin balance after the successful  transaction
                $newBitcoinBalance = $availableBitcoinBalance - $totalAmountInBtc;
                $queryUpdateBalance = "UPDATE register SET available_bitcoin_balance = ? WHERE username = ?";
                $stmtUpdateBalance = $conn->prepare($queryUpdateBalance);
                $stmtUpdateBalance->bind_param("ds", $newBitcoinBalance, $username);
                $stmtUpdateBalance->execute();
            } else {
                echo "<pre>" . print_r($signedTxResponse, true) . "</pre>";
                echo "<h1 style='text-align:center;'>Transaction broadcasting failed</h1>";
            }
        } else {
            echo "<h1 style='text-align:center;'>Transaction creation failed</h1>";
        }
    } else {
        echo "<h1 style='text-align:center;'>Missing form data</h1>";
    }
}
?>

If anyone can help with this it would be greatly appreciated enter image description here Picture of the order successful but yet not broadcastting to the blockchain correctly

Compile Error: Unparenthesized `a ? b : c ? d : e` is not supported. Use either `(a ? b : c) ? d : e` or `a ? b : (c ? d : e)` [closed]

i am using prestashop 8.2 with php 8.1.3

can anyone help to solve the issue below:

'pick_country' => Configuration::get('CEDEASYPARCEL_API_PICKUP_COUNTRY')?Configuration::get('CEDEASYPARCEL_API_PICKUP_COUNTRY'):Configuration::get('PS_SHOP_COUNTRY_ID')?Db::getInstance()->getValue("SELECT `iso_code` FROM `"._DB_PREFIX_."country` WHERE `id_country`='".(int)Configuration::get('PS_SHOP_COUNTRY_ID')."'",true):'MY',

it show error
Compile Error: Unparenthesized a ? b : c ? d : e is not supported. Use either (a ? b : c) ? d : e or a ? b : (c ? d : e)

can anyone help to solve

How can i disable CSRF for some individual pages in Laravel 11.3

I’m using Laravel 11.3 to receive events from Issabel. When I sending data Via Curl in an Eventhandeler PHP AMI file from Issabel, it shows HTTP Code 419 as server respond. ChatGPT told me some changing in code but unfortunately they doesn’t work and are for previous version of Laravel. for example adding some changing in App.php like :

->withMiddleware(function (Middleware $middleware) {
// Completely disable CSRF for testing
$middleware->withoutCsrf();})

that shows this error on other pages but sending data from Issabel works good

( ! ) Fatal error: Uncaught Error: Call to undefined method IlluminateFoundationConfigurationMiddleware::withoutCsrf() in C:UsersAdministratorDesktoptechnotechnoavbootstrapapp.php on line 16

After some googling I use this code:

->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
    'missedcalls',               // Relative path
    'http://192.168.10.29/*',    // Full URL with wildcard
]);})

That works good with other pages but shows http error 419 when i send data from Issabel.
Now the question is how can I disable CSRF for some addresses on Laravel 11.3. as it mentioned in these links Laravel CSRF and Laravel Changes many changes happened in Laravel 11 but there is no good documentation about. I appreciate any help.

How to Create a Responsive Property Table with Shortcode Integration: Issues and Solutions [closed]

I need a way to write a code similar to this table and integrate it into a shortcode. Here’s a simple example of what I need to achieve. I would appreciate everyone’s help in identifying and solving any issues that may arise in the code. Additionally, I’ll list some potential issues in the code for discussion:

Inspired by AqarSky, I aim to replicate its clean property table design with added shortcode integration and dynamic features. https://aqarsky.com/

I tried to replicate the property table design seen on the AqarSky website by writing a simple HTML table structure. I was expecting to create a clean, responsive table that could later be integrated as a shortcode for dynamic use in a website. However, I encountered challenges with making it responsive, dynamically populating data, and ensuring proper functionality for actions like “delete” and “edit.”

composer vendor override – Cannot declare class because the name is already in use

I needed to modify some vendor files, which I did the following way (which was fine in the past):

I copy the vendor file to a vendor-override directory outside the vendor directory and modify it to my needs. Then modify composer.json by adding the original vendor file to “exclude-from-classmap” and add my file to “files”

example:

    "autoload": {
        "psr-4": {
            "App\": "app/",
            "Database\Factories\": "database/factories/",
            "Database\Seeders\": "database/seeders/",
            "Routes\Web\": "routes/web/"
        },
        "exclude-from-classmap": [
            "vendor/area17/twill/src/Models/Model.php",
            "vendor/area17/twill/src/Models/Media.php"
        ],
        "files": [
            "vendor-override/twill/Model.php",
            "vendor-override/twill/Media.php"
        ]
    },

Now my problem is, that “vendor/area17/twill/src/Models/Media.php” inherits from “vendor/area17/twill/src/Models/Model.php”

If I run composer dump-auto, I get the following error:

PHP Fatal error:  Cannot declare class A17TwillModelsModel, because the name is already in use in C:DatabaseSourceDBmodulbau-shopvendor-overridetwillModel.php on line 23

I also tried deleting the vendor Model.php and Media.php file (for testing):
Then I get the following error instead:

In Media.php line 12:
                                            
  [Error]                                   
  Class "A17TwillModelsModel" not found  
                                            

Exception trace:
  at C:DatabaseSourceDBmodulbau-shopvendor-overridetwillMedia.php:12
 require() at C:DatabaseSourceDBmodulbau-shopvendorcomposerautoload_real.php:41
 {closure}() at C:DatabaseSourceDBmodulbau-shopvendorcomposerautoload_real.php:45

To me it seems that vendor-override/twill/Media.php is still referencing to the file in vendor for some reason (perhaps because they were originally in the same folder?)

I tried adding an explicit import (use statement to the Media file, but it did not help. I still get the Class "A17TwillModelsModel" not found error)

vendor-override/twill/Media.php

<?php

namespace A17TwillModels;

use A17TwillModelsModel; // I added this line
use A17TwillServicesMediaLibraryImageService;
use AppModelsSubdomain;
use IlluminateSupportCollection;
use IlluminateSupportFacadesDB;
use IlluminateSupportStr;

class Media extends Model {
  ...

I don’t really understand why it still tries to reference the vendor file, when I explicitly excluded that one from the classmap. Any ideas how to fix that?

How to get user data with PHP8 Google client + Javascript auth code

I have a working Vue application which log user in via Google Javascript SDK. This get a token/code (I really dont how they call it). Then I send this token to the PHP application which uses Google api php client but then I really dont know what to do. Documentation does not show which class or method to use. I tried something like this:

$this->google_client = new Client();
$this->google_client->setClientId(config('services.google')['client_id']);
$this->google_client->setClientSecret(config('services.google')['client_secret']);

//$this->google_client->setAccessToken($token);
$this->google_client->addScope('openid');
$this->google_client->addScope('email');
//$this->google_client->addScope('profile');
$access_token = $this->google_client->fetchAccessTokenWithAuthCode($token);

Log::info($access_token);

$this->google_client->setAccessToken($access_token);

But the Log store this:

[
  'error' => 'invalid_grant',
  'error_description' => 'Bad Request',
]  

PHP SQLSRV STORED PROC – Hanging Browser

I have a stored procedure that I would like to run from a simple button click.
The stored procedure takes 5-10 mins to run direct from SMSS.

I’m not looking to return any results to the browser, so I would prefer if the browser didn’t hang whilst the stored procedure was running.
I’m using the following to trigger the SP on button click.

$sp_exec = "EXEC [sp_name]";
$sp_exec_qry = sqlsrv_query($conn, $sp_exec];

Is there a way to stop php waiting for the script to finish?
to background it somehow?
Apologies if this is very amateur, just learning as I go 🙂
Thanks

How to Implement Authentication with the NIMLAB Crypto Exchange API in PHP?

I’m trying to implement authentication to connect with the NIMLAB crypto exchange, following their official documentation: NIMLAB API Docs.

However, I keep running into issues with the authentication and signature generation. Unfortunately, the solutions I’ve tried so far are not working.

The NIMLAB support team provided a Python example, which they claim works perfectly:

import json
import hashlib
import asyncio
import aiohttp
import logging

from aiohttp.client_exceptions import ContentTypeError, ClientConnectorError
from urllib.parse import urlencode, quote

class NIMLABAPI:
    def __init__(self, apiUrl, apiKey, apiSecret):
        if not apiUrl:
            raise ValueError('apiUrl is required in class ExchangerAPI')
        if not apiKey:
            raise ValueError('apiKey is required in class ExchangerAPI')
        if not apiSecret:
            raise ValueError('apiSecret is required in class ExchangerAPI')

        self.config = {
            "apiUrl": apiUrl,
            "apikey": apiKey,
            "secret": apiSecret
        }

        self.session = aiohttp.ClientSession()

    def generate_hash(self, get_params, post_params):

        for key in get_params:
            if isinstance(get_params[key], list):
                get_params[key] = [str(value) for value in get_params[key]]
            else:
                get_params[key] = str(get_params[key])

        params = {**get_params, **post_params}
        checksum_params = hashlib.sha256(json.dumps(params, ensure_ascii=False, separators=(',', ':')).encode()).hexdigest()
        HASH = hashlib.sha256((checksum_params + self.config['secret']).encode()).hexdigest()
        return HASH

    async def call(self, method, param=None, rewriteConfig=None):
        if param is None:
            param = {}
        get = param.get('get', {})
        post = param.get('post', {})
        post_out =  json.dumps(post, ensure_ascii=False)

        if not isinstance(get, dict):
            return {"errorCode": 20, "message": 'Error invalid "get" params must be object'}
        if not isinstance(post, dict):
            return {"errorCode": 21, "message": 'Error invalid "post" params must be object'}

        configService = {**self.config, **(rewriteConfig or {})}
        method_parts = method.split(':')
        typeMethod = 'POST'

        if len(method_parts) == 2:
            typeMethod, method = method_parts[0].upper(), method_parts[1]
        else:
            method = method_parts[0]

        if typeMethod == 'GET':
            get['time'] = int(1000 * asyncio.get_event_loop().time())

        url_params = "&".join(f"{key}={value}" if not isinstance(value, list) else "&".join(f"{key}[]={item}" for item in value) for key, value in get.items())

        url = f"{configService['apiUrl']}{method}?{url_params}" if url_params else f"{configService['apiUrl']}{method}"

        HASH = self.generate_hash(get, post)
        print(f"URL: {url}")
        async with self.session.request(typeMethod, url, headers={
            'cache-control': 'no-cache',
            'apikey': configService['apikey'],
            'hash': HASH,
            'Content-Type': 'application/json'
        }, data=post_out) as response:
            while True:
                try:
                    if response.status in [502, 504, 409]:
                        logging.warning(f"Error {response.status}: {response.reason}. Retrying in a while...")
                        await asyncio.sleep(15)
                        continue

                    if response.status != 200:
                        cf_mitigated = response.headers.get('cf-mitigated')
                        if cf_mitigated:
                            ray_id = response.headers.get('cf-ray', 'unknown')
                            raise Exception(f'CloudFlare mitigation required "{cf_mitigated}". RayID: {ray_id}. '
                                            'Ask support to whitelist your IP.')

                        reason = response.reason or 'Unknown error'
                        raise Exception(f'Error API: {response.status} - {reason}')

                    if 'application/json' not in response.headers.get("content-type", ""):
                        text = await response.text()
                        raise Exception(f'Error: Response not JSON: {text}')

                    text = await response.text()
                    response_data = json.loads(text)
                    if not response_data.get('success') or not response_data.get('data'):
                        error_msg = response_data.get('error', 'Unknown error')
                        raise Exception(f'Error API: {error_msg}')

                    return json.dumps(response_data.get('data', {}))

                except aiohttp.ClientError as error:
                    logging.exception("API call error", exc_info=error)

    async def close(self):
        await self.session.close()

I need to adapt this logic to PHP. I’ve already tried using hash_hmac and various approaches to create the signature, but nothing seems to work.

Can anyone help me convert this code to PHP or guide me on how to properly implement authentication with signature generation?

API DOC: https://nimlab.eu/service/api-docs/#/

Thank you in advance!

Yeah, I forgot to include the code:

<?php

class NIMLABAPI {
    private $apiUrl;
    private $apiKey;
    private $apiSecret;

    public function __construct($apiUrl, $apiKey, $apiSecret) {
        if (empty($apiUrl)) {
            throw new InvalidArgumentException('apiUrl is required');
        }
        if (empty($apiKey)) {
            throw new InvalidArgumentException('apiKey is required');
        }
        if (empty($apiSecret)) {
            throw new InvalidArgumentException('apiSecret is required');
        }

        $this->apiUrl = $apiUrl;
        $this->apiKey = $apiKey;
        $this->apiSecret = $apiSecret;
    }

    private function generateHash($getParams, $postParams) {
        foreach ($getParams as $key => &$value) {
            if (is_array($value)) {
                $value = array_map('strval', $value);
            } else {
                $value = strval($value);
            }
        }

        $params = array_merge($getParams, $postParams);
        $checksumParams = hash('sha256', json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
        $hash = hash('sha256', $checksumParams . $this->apiSecret);
        return $hash;
    }

    public function call($method, $params = [], $rewriteConfig = []) {
        $get = $params['get'] ?? [];
        $post = $params['post'] ?? [];

        if (!is_array($get)) {
            return ["errorCode" => 20, "message" => 'Error: "get" params must be an array'];
        }
        if (!is_array($post)) {
            return ["errorCode" => 21, "message" => 'Error: "post" params must be an array'];
        }

        $configService = array_merge([
            'apiUrl' => $this->apiUrl,
            'apikey' => $this->apiKey,
            'secret' => $this->apiSecret
        ], $rewriteConfig);

        $methodParts = explode(':', $method);
        $typeMethod = count($methodParts) === 2 ? strtoupper($methodParts[0]) : 'POST';
        $method = count($methodParts) === 2 ? $methodParts[1] : $methodParts[0];

        if ($typeMethod === 'GET') {
            $get['time'] = intval(microtime(true) * 1000);
        }

        $urlParams = http_build_query($get);
        $url = $configService['apiUrl'] . $method . ($urlParams ? '?' . $urlParams : '');

        $hash = $this->generateHash($get, $post);

        $headers = [
            'cache-control: no-cache',
            'apikey: ' . $configService['apikey'],
            'hash: ' . $hash,
            'Content-Type: application/json'
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $typeMethod);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        if ($typeMethod === 'POST') {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post, JSON_UNESCAPED_UNICODE));
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);

        if ($httpCode !== 200) {
            $error = "Error: HTTP $httpCode";
            if (strpos($contentType, 'application/json') !== false) {
                $responseData = json_decode($response, true);
                $error = $responseData['error'] ?? $error;
            }
            curl_close($ch);
            throw new Exception($error);
        }

        curl_close($ch);
        $responseData = json_decode($response, true);

        if (empty($responseData['success']) || empty($responseData['data'])) {
            throw new Exception('API Error: ' . ($responseData['error'] ?? 'Unknown error'));
        }

        return $responseData['data'];
    }
}

?>

DQL query : LOWER function suddenly stopped working [duplicate]

Recently updated a backend service from a Symfony 5.4 / php 7 to a Symfony 6.4 / php 8.3 config.

The database is using Postgresql 14.

Since the doctrine queries I have that include LOWER stopped working, for instance:

$qb->where(‘i.title ‘ . ‘LIKE LOWER(:keyWord)’)

I wrapped them in a try / catch but I don’t even have an error coming, just no response at all (another error introduced on purpose, like a misspell does send back an error).

As soon as I just remove the “LOWER” everything works fine. Seems like just the fact it’s written in the query blocks everything.

I must underline that it’s not similar to other cases I saw where LOWER is written but has no effect, in my case it’s like it’s stopping the whole process, nothing happens like the query isn’t sent.

I updated the database to Postgresql 17 but it had no effect.

Any help would… help!

Thanks

  • Upgrade to Postgresql 17
  • Clear various caches
  • Try the SQL request directly in the database adminer (it works)
  • Try the solution from “Doctrine Query Builder LOWER not working”