Apache shutdown unexpectedly. This may be due to a blocked port, missing dependencies, improper privileges, a crash, or a shutdown by another method

Apache shutdown unexpectedly. This may be due to a blocked port, missing dependencies, improper privileges, a crash, or a shutdown by another method.
How can I solve this problem?
I already chagned the cong=fig file “Listen port: 80 to 8800”
I also changed the “httpd-ssl.conf” file too

I want the proper solution of it.
Please help me

Click Attribute link in localstorage than search data in datatable

i have a page that consist of two column, left column display datatable and right column display localstorage data, when i click the row in datatable, it will store in localstorage display on the left column, i need when i click localstorage row data, that data go to search in datatable,
please need your advice how can make it

Below screenshoot about column datatable and localstorage

enter image description here

Look For Ten Using PHP Programming Language

enter image description hereI am trying to write a program to create a function that takes two arguments. Both arguments are integers, a and b. And it will return true if one of them is 10 or if their sum is 10. And I am doing it on “Codemama” platform. The numbers are given on the console area in codemama platform and the output is not showing as expected. Do I have to call “lookForTen” function? Because if I have to then I have to pass the arguments after calling the function. But as I said it’s already available in the console. And the output is supposed to be “true” but it’s not showing anything Here’s the code below. Please help me find the mistake.

<?php
    # Write your PHP code from here

    $a = trim(fgets(STDIN)); 
    $b = trim(fgets(STDIN));


function lookForTen($a, $b):bool{

    if($a + $b == 10){

        return true;
        
    }
    
    else{

        return false;
        
    }
}

?>

quiz image display query [closed]

In order to fulfil my demand, I must upload photographs outside of the programme, and the image location must be recorded in the question, option, and answer columns of a PostgreSQL database. then an image showing the specific procedure will be displayed at the front end? I need code for React and Node, and I also need to know how to make a table.

my requirement is upload images in outside’s the application and image path will be stored in postgresql database tables are question, option and answer. then image will be displaying in front-end that certain path how to do it? i need code for React js and node js and how to create the table?

How to handle Cookies/Sessions if PHP-backend is on a different server

I have a general question about handling cookies if you are working on two servers while developing (one server for front- and backend)
I have build a webapplication with a login system. There are two main routes:

“/” is the landing page for the public with option to login or create an account

“/dashboard” a protected starting page after you logged in

If you register (create a new Account), the app automaticly logs you in (and therefore redirects you to “/dashboard”

All of this works fine. To avoid users from entering the portected area by manually typing the /dashboard route into the browsers url window i want it to check instantly, wether a user is logged or not.

Allthough during the process of creating an account, the $_SESSION variable for the logged user is set, right after redirecting to “/dashboard” (and therefore instant check for the same $_SESSION variable that was set milliseconds ago) i can see out of the response of the checking that this particular $_SESSION variable is not set.

So is there anything special i need to keep in mind when having the backend on a different server?

Why am i emphasising the different server so much?
Well, my application already worked fine. I used to work with plain JS and plain PHP. That was easy to work with because is just had my complete project into the htdocs folder of XAMPPs apache webserver.

I am refactoring my application from plain JS to Vue 3.

So this is different now:

  • My Vue CLI runs a webserver for the vue application on “localhost:8080”
  • My backend stays in htocs because, well, i need a server that runs php on “localhost”
  • In JS (and Vue) i work with fetch(). As Endpoint for the Php i used to use a reltive path (bc it was all in one project directory) like fetch("../src/backend/main.php") and now i use the path to the localhost server like fetch("http/localhost/backend/main.php")
  • Because localhost:8080 is for my backend different from “localhost” i have set the following headers in my backend:

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type, Credentials");

session_start();

Because those are the only things that are new i assume that my problem has to do with the additional server for my development environment but if you see another cause please let me know.

I want to emphasise that every other communication between front- and backend works perfectly fine, its just that i ahve the feeling that sessions are treated differently now and i would love to know why.

PHP spot API poloniex

Poloniex new API

I can’t get the right answer. SDK javascript
who uses PHP help, what is the problem?
Exchange support is not responding.

<php?
require_once('api_key.php');
$apikey =api_key();
$secret =api_secret();

$ts=server_time();
$timestamp=timestamp();
 
$par="limit=5&signTimestamp=".$timestamp."&symbol=TRX_BTC";
$apar=array("limit=".urlencode('5'), "signTimestamp=".urlencode($timestamp), "symbol=".urlencode('TRX_BTC'));
$paru=$apar[0];
for ($i=1; $i<count($apar); $i++){
    $paru=$paru.'&'.$apar[$i];
}
echo "paru=".$paru."rn";
//$paru=urlencode($par);
$auth="GETn"."ordersn".$paru;
$sign = base64_encode(hash_hmac('sha256', $auth, $secret));

$baseurl='https://api.poloniex.com';
$url=$baseurl.'/orders'.'?'.$par;

    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
 
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

    curl_setopt($ch, CURLOPT_HEADER, TRUE);
    $headers=array("Content-Type: application/json","key: ".$apikey, "signTimestamp: ".$timestamp,"signature: ".$sign);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);    
    curl_setopt($ch, CURLOPT_URL, $url);
 
curl_setopt($ch, CURLOPT_FAILONERROR, 1); //stop if an error occurred
$res=curl_exec($ch); //store the content in variable
$rescode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if(!curl_errno($ch)){
    header ("Content-type: ".curl_getinfo($ch, CURLINFO_CONTENT_TYPE)."");
    echo $res;
} else {
    $error = curl_error($ch).'('.curl_errno($ch).')';
    echo 'Curl error: ' . $error."rn";
}

    curl_close($ch);

//Result: error 401
I tried to sign all parameters of the urlencode string differently. Constantly 401 error

Undefined variable $no_antrian

I want to create a queuing system in Laravel but I have problems with coding and don’t understand how to set up the coding correctly. Can anyone help me?

public function store(Request $request ){

        $latestAntrian = Antrian::where('layanan', $this->layanan)
            ->where('tanggal_antrian', now()->toDateString())
            ->latest('id_antrian')
            ->first();

         if (!$latestAntrian) {
            if($this->layanan === 'anak'){
                $this->no_antrian = 'A1';
            } elseif ($this->layanan === 'ibu'){
                $this->no_antrian = 'B1';
            } elseif ($this->layanan === 'lansia'){
                $this->no_antrian = 'C1';
            }
            $this->tanggal_antrian = now()->toDateString();
        } else {

            $kode_awal = substr($latestAntrian->no_antrian, 0, 1);
            $angka = (int) substr($latestAntrian->no_antrian, 1);
            $angka +=1;
            $no_antrian = $kode_awal . $angka;
            $tanggal_antrian = $latestAntrian->tanggal_antrian;
        }

        $data                   = new Antrian;
        $data->no_antrian       = ($no_antrian);
        $data->nama             = $request->get('nama');
        $data->no_hp            = $request->get('no_hp');
        $data->layanan          = $request->get('layanan');
        $data->tanggal_antrian  = ($tanggal_antrian);
        $data->save();
   
         Alert::success('Data Berhasil Ditambah');
 
         return redirect()->route('antrianuser')->with([
             'success' => 'Data Berhasil Di Tambah'
         ]);
    }

help me by improving this code

eliminate a dropdown menu and instead show the form by default

the following code is a register or login page in my website it has a option to register as a vendor or as a client , I could delet the client section as i wanted but i want to see the form the minute a user clicks on register.
this is the addres that you can check what i mean
register.lida98.com

this is the form page that i found and i attach the .js file that is related to it below

“>

<p class="form-row form-group form-row-wide">
    <label for="company-name"><?php esc_html_e( 'Shop Name', 'dokan-lite' ); ?> <span class="required">*</span></label>
    <input type="text" class="input-text form-control" name="shopname" id="company-name" value="<?php echo ! empty( $data['shopname'] ) ? esc_attr( $data['shopname'] ) : ''; ?>" required="required" />
</p>

<p class="form-row form-group form-row-wide">
    <label for="seller-url" class="pull-left"><?php esc_html_e( 'Shop URL', 'dokan-lite' ); ?> <span class="required">*</span></label>
    <strong id="url-alart-mgs" class="pull-right"></strong>
    <input type="text" class="input-text form-control" name="shopurl" id="seller-url" value="<?php echo ! empty( $data['shopurl'] ) ? esc_attr( $data['shopurl'] ) : ''; ?>" required="required" />
    <small><?php echo esc_url( home_url() . '/' . dokan_get_option( 'custom_store_url', 'dokan_general', 'store' ) ); ?>/<strong id="url-alart"></strong></small>
</p>

<?php

/**
 * Store Address Fields
 */

if ( 'on' === dokan_get_option( 'enabled_address_on_reg', 'dokan_general', 'off' ) ) {
    dokan_seller_address_fields( false, true );
}
/**
 * @since 3.2.8
 */
do_action( 'dokan_seller_registration_after_shopurl_field', [] );
?>

<p class="form-row form-group form-row-wide">
    <label for="shop-phone"><?php esc_html_e( 'Phone Number', 'dokan-lite' ); ?><span class="required">*</span></label>
    <input type="text" class="input-text form-control" name="phone" id="shop-phone" value="<?php echo ! empty( $data['phone'] ) ? esc_attr( $data['phone'] ) : ''; ?>" required="required" />
</p>

<?php
$show_terms_condition = dokan_get_option( 'enable_tc_on_reg', 'dokan_general' );
$terms_condition_url  = dokan_get_terms_condition_url();

if ( 'on' === $show_terms_condition && $terms_condition_url ) {
    ?>
    <p class="form-row form-group form-row-wide">
        <input class="tc_check_box" type="checkbox" id="tc_agree" name="tc_agree" required="required">
        <label style="display: inline" for="tc_agree">
            <?php
            printf(
            /* translators: %1$s: opening anchor tag with link, %2$s: an ampersand %3$s: closing anchor tag */
                __( 'I have read and agree to the %1$sTerms %2$s Conditions%3$s.', 'dokan-lite' ),
                sprintf( '<a target="_blank" href="%s">', esc_url( $terms_condition_url ) ),
                '&amp;',
                '</a>'
            );
            ?>
        </label>
    </p>
    <?php
}
do_action( 'dokan_seller_registration_field_after' );
?>
<label class="radio">
    <input type="radio" name="role" value="seller"<?php checked( $role, 'seller' ); ?>  class="dokan-role-seller">
    <?php esc_html_e( 'I am a vendor', 'dokan-lite' ); ?>
</label>
<?php do_action( 'dokan_registration_form_role', $role ); ?>

this is the js part :

(()=>{var e,r;e=jQuery,r={init:function(){var r=e(“form.register”);e(“.user-role input[type=radio]”,r).on(“change”,this.showSellerForm),e(document).on(“dokan_event_seller_registration_form”,this.showSellerForm),e(“.tc_check_box”,r).on(“click”,this.onTOC),e(“#shop-phone”,r).on(“keydown”,dokan_sanitize_phone_number),e(“#company-name”,r).on(“focusout”,this.generateSlugFromCompany),e(“#seller-url”,r).on(“keydown”,this.constrainSlug),e(“#seller-url”,r).on(“keyup”,this.renderUrl),e(“#seller-url”,r).on(“focusout”,this.checkSlugAvailability),this.validationLocalized(),this.handlePasswordStrengthObserver(),e(document).trigger(“dokan_event_seller_registration_form”)},validate:function(r){e(“form.register”).validate({errorPlacement:function(r,t){e(t).closest(“.form-group”).addClass(“has-error”).append(r)},success:function(r,t){e(t).closest(“.form-group”).removeClass(“has-error”)},submitHandler:function(e){e.submit()}})},showSellerForm:function(){“seller”===e(this).val()?(e(“.show_if_seller”).find(“input, select”).removeAttr(“disabled”),e(“.show_if_seller”).slideDown(),e(“.tc_check_box”).length>0&&e(“button[name=register]”).attr(“disabled”,”disabled”),e(“.user-role .dokan-role-seller”).prop(“checked”,!0)):(e(“.show_if_seller”).find(“input, select”).attr(“disabled”,”disabled”),e(“.show_if_seller”).slideUp(),e(“.tc_check_box”).length>0&&e(“button[name=register]”).removeAttr(“disabled”),e(“.user-role .dokan-role-customer”).prop(“checked”,!0))},onTOC:function(){e(this).val(),e(this).prop(“checked”)?(e(“input[name=register]”).removeAttr(“disabled”),e(“button[name=register]”).removeAttr(“disabled”),e(“input[name=dokan_migration]”).removeAttr(“disabled”)):(e(“input[name=register]”).attr(“disabled”,”disabled”),e(“button[name=register]”).attr(“disabled”,”disabled”),e(“input[name=dokan_migration]”).attr(“disabled”,”disabled”))},generateSlugFromCompany:function(){var r=getSlug(e(this).val());e(“#seller-url”).val(r),e(“#url-alart”).text(r),e(“#seller-url”).focus()},constrainSlug:function(r){e(this).val(),-1!==e.inArray(r.keyCode,[46,8,9,27,13,91,109,110,173,189,190])||65==r.keyCode&&!0===r.ctrlKey||r.keyCode>=35&&r.keyCode<=39||(r.shiftKey||(r.keyCode<65||r.keyCode>90)&&(r.keyCode<48||r.keyCode>57))&&(r.keyCode<96||r.keyCode>105)&&r.preventDefault()},checkSlugAvailability:function(){var r=e(this),t={action:”shop_url”,url_slug:r.val(),_nonce:dokan.nonce};if(“”!==r.val()){var o=r.closest(“.form-row”);o.block({message:null,overlayCSS:{background:”#fff url(“+dokan.ajax_loader+”) no-repeat center”,opacity:.6}}),e.post(dokan.ajaxurl,t,(function(r){!0===r.success?(e(“#url-alart”).removeClass(“text-danger”).addClass(“text-success”),e(“#url-alart-mgs”).removeClass(“text-danger”).addClass(“text-success”).text(dokan.seller.available),e(“.woocommerce-form-register__submit”).prop(“disabled”,!1)):(e(“#url-alart”).removeClass(“text-success”).addClass(“text-danger”),e(“#url-alart-mgs”).removeClass(“text-success”).addClass(“text-danger”).text(dokan.seller.notAvailable),e(“.woocommerce-form-register__submit”).prop(“disabled”,!0)),o.unblock()}))}},renderUrl:function(){e(“#url-alart”).text(e(this).val())},validationLocalized:function(){var r=DokanValidateMsg;r.maxlength=e.validator.format(r.maxlength_msg),r.minlength=e.validator.format(r.minlength_msg),r.rangelength=e.validator.format(r.rangelength_msg),r.range=e.validator.format(r.range_msg),r.max=e.validator.format(r.max_msg),r.min=e.validator.format(r.min_msg),e.validator.messages=r},handlePasswordStrengthObserver:function(){const e=document.querySelector(“.woocommerce-form-register .password-input”),r=[“good”,”strong”];e&&new MutationObserver(((e,t)=>{for(const t of e)r.some((e=>t.target.classList.contains(e)))&&this.ensureShopSlugAvailability()})).observe(e,{subtree:!0,childList:!0})},ensureShopSlugAvailability:function(){const r=e(“#url-alart-mgs”).hasClass(“text-success”),t=e(‘.vendor-customer-registration input[name=”role”]:checked’),o=e(“.woocommerce-form-register__submit”);”seller”===t.val()&&(r?o.prop(“disabled”,!1):o.prop(“disabled”,!0))}},e((function(){if(window.Dokan_Vendor_Registration=r,window.Dokan_Vendor_Registration.init(),e(“.show_if_seller”).find(“input, select”).attr(“disabled”,”disabled”),e(“.woocommerce ul”).hasClass(“woocommerce-error”)&&!e(“.show_if_seller”).is(“:hidden”)){var t=e(“form.register”);e(“.user-role input[type=radio]”,t).trigger(“change”)}e(“.tc_check_box”).length>0&&(e(“input[name=dokan_migration]”).attr(“disabled”,”disabled”),e(“input[name=register]”).attr(“disabled”,”disabled”))}))})();

what should i change so i the register form as a vendor shows by default once you click on the register button?
thanks

I tried .proped(check) values form 0 to 1 but it did not work , i am not very familiar with js so i did not try other methods

How to print data on Angular coming from Laravel API relationship with one to many Models

I have Angular App connected with Laravel API. In Laravel API there are one to many relationship between Employee and Salary Models. now I need print Salary Model data on Angular app. so, I try in this way

<div class="basic-info">
    <p>Employee Name : {{employee.first_name}}</p>
    <p>Date of Birth :</p>
    <p>Gender :</p>
    <p>Hire Date :</p>
</div> 
 <div class="salary-topic">
    <h4><b>Salary Details</b></h4>
</div>
<div class="salary-details">
    <table class="table">
        <thead>
            <tr>
                <th scope="col">salary {{employee.salary}}</th>
                <th scope="col">From Date{{employee.from_date}}</th>
                <th scope="col">To Date{{employee.to_date}}</th>
            </tr>
        </thead>
</table>
</div>

my data.service.ts is like this

 getEmployeeById(id: string){
    return this.httpClient.get('http://127.0.0.1:8000/api/employee/'+id);
  }

and employee-by-id.ts is

 getData() {
    this.dataService.getEmployeeById(this.id).subscribe(res => {
     // console.log(res);
     this.data = res;
     this.employee = this.data;
    })
  }

my Employee model data is printing well. but relathionship Salary Model is not printing. in browser element printing both model data well in json format. how could I fix this problem?

How To Get Filename In Google Service Drive?

I try to fetch my google drive folder image use in Google_Service_Drive ..i Cannot Understand it’s not execute image name fetch it’s code is fine.i’think but why it’s not fetch any image..

There is a problem with my code, I need to find it..and how can I do this?

function testtt(){
$version        = '3.7.3';
    $plugin_name    = 'wpgsi';

    $common         = new Wpgsi_common($plugin_name, $version);             
    $wpgsi_events   = new Wpgsi_Events($plugin_name, $version, $common);
    $googleSheet    = new Wpgsi_Google_Sheet($plugin_name, $version, $common); 

    $Wpgsi_Images   = new Wpgsi_Images($plugin_name, $version, $wpgsi_events, $googleSheet);
    $client         = $Wpgsi_Images->getClient();
    $service        = new Google_Service_Drive( $client );

    $sub_folders = array(
                            '...........................rt'
                        );
    $folders_query = implode("' or parents in '", $sub_folders );
    echo $q."<br>";
    echo "<pre>";
    print_r($folders_query);
    echo "</pre>";

    $imagename = "Armchair_Whitewash_WB_R01.png";   
    $imgname = preg_replace( '/[^a-z0-9.-_]/i', ' ', $imagename );
    $q       = "name contains '". $imgname ."' and trashed = false and (parents in '". $folders_query ."')";

    echo $q;
    $request = $service->files->listFiles( [
        'q'  => $q,
    ]);
    echo $q."<br>";
    echo "<pre>";
    print_r($request);
    echo "</pre>";
}
add_action('init','testtt');

how to set different font sizes within in a cell

$rowIndex = 1;
foreach ($request->warehouses as $warehouse) {
    $whId = $asset['id_fixed_asset'];
    $warehouse = Warehouse::find($whId);
    if ($warehouse) {
            foreach ($rowDetails as $rowDetail) {
                $fieldName = $rowDetail['id_field'];
                $fieldValue = $warehouse->$fieldName;
                $fontSize = $rowDetail['font_size'];
                $cellData = "$fieldValuen";
                $sheet->setCellValue('A' . $rowIndex, $cellData);
                $sheet->getStyle('A' . $rowIndex)->getAlignment()->setWrapText(true);
                $sheet->getStyle('A' . $rowIndex)->getFont()->setSize($fontSize);
                
                $rowIndex++;
            }
        
    }
}

In this code, field_value has a different font_size and is separated in each cellresult

i want to make an export excel file with format where each field_value has a font_size value that has been set and the field_values are separated by a new line in the cell (wrap text), while the new data from each fixed_asset will be separated in a new cell. For example like this:
expectations

Running multiple projects using docker with one docker-compose but can only reach the frontend project

I am having trouble setting docker to run 2 projects on a single container or on a single docker-compose.yml

So I am using php slim4 for the backend and frontend the main difference is frontend will use twig for the view. When I run them separately using their own docker-compose and nginx it works fine and no issue. But when i run it on a single docker-compose.yml which includes the frontend and backend. only the frontend works and everytime i try to do a call to the backend api i get bad gates or as if the frontend intervenes and says the route doesnt exist. localhost is fine but localhost/api/v1/test cannot reach as error message

homepage link: localhost
Fatal error: Uncaught SlimExceptionHttpNotFoundException: Not found. in /frontend/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php on line 76

I checked the container and it says everything is ok.

I am just trying to run it locally for now and this my set up

- project-directory
  - backend
    - docker
      - php
        - Dockerfile
        - php-fpm.conf
    - web
      - index.php
    - ... (other backend files and directories)
  - frontend
    - docker
      - php
        - Dockerfile
        - php-fpm.conf
    - web
      - index.php
    - ... (other frontend files and directories)
  - nginx
    - nginx.conf
  - docker-compose.yml

and in my docker-compose.yml

version: '3.9'

services:
  backend:
    container_name: backend
    build:
      context: ./backend
      dockerfile: ./docker/php/Dockerfile
    ports:
      - 9001:9000
    volumes:
      - ./backend:/backend

  frontend:
    container_name: frontend
    build:
      context: ./frontend
      dockerfile: ./docker/php/Dockerfile
    ports:
      - 9000:9000
    volumes:
      - ./frontend:/frontend

  nginx:
    image: nginx
    container_name: nginx
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - /etc/hosts:/etc/hosts        # Add this line
    ports:
      - 80:80
    depends_on:
      - backend
      - frontend

nginx.conf

events {
  worker_connections 1024;
}
http {
  upstream backend {
    server backend:9001;
  }

  upstream frontend {
    server frontend:9000;
  }

  server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    server_tokens off;

    root /frontend/web;
    index index.php;

   location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    
    location /api/v1 {
        proxy_pass http://backend:9001;
    }

    location ~ .php$ {
        include fastcgi_params;
        fastcgi_pass frontend;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
  }

  server {
    listen 80;
    server_name backend;

    root /backend/web;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ .php$ {
        include fastcgi_params;
        fastcgi_pass backend;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
  }
}

dockerfile for frontend and it is the same for the backend but using ‘backend’

FROM php:8.2-fpm

# Install Xdebug
RUN pecl install xdebug 
    && docker-php-ext-enable xdebug

# Copy the php config file
COPY ./docker/php/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf

# Copy the application code
COPY . /frontend

VOLUME ["/frontend"]

the php-fpm.conf is the same for both as i just copied it next to dockerfile for both frontend and backend

[www]
user = www-data
group = www-data

listen = 127.0.0.1:9000
pm = dynamic
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

Really grateful if you could help me out, i have been stuck on this for a few days now. thank you

Laravel l5-swagger api-docs.json file not found

I am installed

composer require "darkaonline/l5-swagger:5.6.*",

and i have a api-docs.json from a swagger that I added to storage/api-docs/api-docs.json.
But when i go to

http://127.0.0.1:8000/api/documentation

I got error

Fetch error Not Found http://127.0.0.1:8000/docs/api-docs.json

I tried to run

php artisan l5-swagger:generate

but it logically returns an error

Required @OAInfo() not found

because it wants me to manually enter all the api information in the classes, but my api is quite large so it will take me a long time to rewrite it.

Can darkaonline/l5-swagger just read my api-docs.json file from the storage?

How to allow re-submission of a form without requiring a page refresh for new token generation?

I have implemented a security system for a WordPress site form that involves generating a unique token for every form submission. The current flow is:

When a user goes to the website with the form, several security measures kick in, including the generation of a unique token.
Once the form is submitted, a new token isn’t generated. This means that if a user made some errors or wants to re-submit for any reason, they’d need to refresh the entire page to generate a new token.
Given the following code logic for token generation, validation, and cleanup:

Database Table Creation for Storing Tokens:

function create_token_table() {
    global $wpdb;
    $charset_collate = $wpdb->get_charset_collate();
    $sql = "CREATE TABLE IF NOT EXISTS `{$wpdb->base_prefix}CF7_unique_tokens` (
        id mediumint(9) NOT NULL AUTO_INCREMENT,
        token varchar(255) NOT NULL,
        salt varchar(16) NOT NULL,
        timestamp datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
        PRIMARY KEY  (id)
    ) $charset_collate;";
    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta($sql);
}
add_action('init', 'create_token_table');

Generating a Unique Token:

function generate_token() {
    if (!function_exists('random_bytes') || !function_exists('openssl_encrypt') || !defined('AUTH_KEY')) {
        return false;
    }
    $token = bin2hex(random_bytes(32));
    $salt = random_bytes(8);
    $salt_hex = bin2hex($salt);
    $encrypted_token = openssl_encrypt($token, 'aes-256-cbc', AUTH_KEY, 0, $salt_hex);
    global $wpdb;
    $success = $wpdb->insert($wpdb->prefix . 'CF7_unique_tokens', [
        'token' => $encrypted_token,
        'salt' => $salt_hex,
        'timestamp' => current_time('mysql'),
    ]);
    return $success ? $encrypted_token : false;
}

Cleaning Up Old Tokens:

function cleanup_old_tokens() {
    global $wpdb;
    $expiration = date('Y-m-d H:i:s', strtotime('-24 hours'));
    $wpdb->query($wpdb->prepare("DELETE FROM `{$wpdb->prefix}CF7_unique_tokens` WHERE timestamp < %s", $expiration));
}
add_action('init', 'cleanup_old_tokens');

Adding the Generated Token to Form as a Hidden Field:

function add_token_hidden_field($hidden_fields) {
    $token = generate_token();
    if (!$token) {
        return $hidden_fields;
    }
    $hidden_fields['form_token'] = $token;
    $hidden_fields['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    return $hidden_fields;
}
add_filter('wpcf7_form_hidden_fields', 'add_token_hidden_field');

Validating the Submitted Token:

function validate_token_and_keywords($spam) {
    global $wpdb;
    if (!isset($_POST['form_token'])) {
        return true;
    }
    $token = $_POST['form_token'];
    if (!is_token_valid($token, $wpdb)) {
        return true;
    }
    delete_token($token, $wpdb);
    return $spam;
}

Deleting a Token from the Database:

function delete_token($token, $wpdb) {
    $wpdb->delete("{$wpdb->prefix}CF7_unique_tokens", array('token' => $token));
}

Checking Token’s Validity:

function is_token_valid($token, $wpdb) {
    $result = $wpdb->get_row($wpdb->prepare("SELECT * FROM `{$wpdb->prefix}CF7_unique_tokens` WHERE token = %s", $token));
    if (!$result) {
        return false;
    }
    return true;
}

I’d like to address two main concerns:

  • How can I prevent the user from needing to refresh the entire page?
  • How can I ensure that the user can submit the form again (after the first submission) without token-related issues?
    In essence, I want the form to be user-friendly by allowing re-submissions without a full page refresh but also ensure it remains secure against spam or malicious attacks. Any recommendations on the best approach or adjustments to the current logic would be greatly appreciated.