Click here to Skip to main content
15,887,267 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
i have a php script that executes a vbscript , the PHP scrip runs in xaamp, the issue is that the PHP script is executing successfully without executing the VBScript, when I trigger the VBScript manually (double click , it works fine)

bellow is my VBScript and PHP script

VBSCRIPT:
Option Explicit

Dim objFSO, objExcel, objFolder, objFile, strSheetName
Dim objSheet, objRange, objCell, intRow, intCol, objTargetSheet, objWorkbook
Dim objErrorLog, strErrorLogPath, strErrorMessage

strErrorLogPath = "C:\xampp\htdocs\HTML\SSProcess\ErrorLogs.txt"

' Set the objects for Excel and File System
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = False

' Error handling for logging and continue
On Error Resume Next

' Open the error log for writing
Set objErrorLog = objFSO.OpenTextFile(strErrorLogPath, 8, True)

For Each objFile In objFSO.GetFolder("C:\xampp\htdocs\HTML\SSProcess\ExcelFiles").Files
    If LCase(objFSO.GetExtensionName(objFile.Name)) = "xlsx" Then
        Set objWorkbook = objExcel.Workbooks.Open(objFile.Path)
        
        ' Find the sheet with the name containing "R" and having the highest numeric value
        Dim maxNumber, currentNumber
        maxNumber = -1
        strSheetName = ""
        
        For Each objSheet In objWorkbook.Sheets
            ' Check if the sheet name contains "R" followed by numeric characters
            Dim sheetName, positionOfR
            sheetName = objSheet.Name
            positionOfR = InStr(sheetName, "R")
            
            If positionOfR > 0 Then
                Dim numericPart
                numericPart = Mid(sheetName, positionOfR + 1)
                If IsNumeric(numericPart) Then
                    currentNumber = CInt(numericPart)
                    If currentNumber > maxNumber Then
                        maxNumber = currentNumber
                        strSheetName = objSheet.Name
                    End If
                End If
            End If
        Next

        If strSheetName <> "" Then
            Set objSheet = objWorkbook.Sheets(strSheetName)
            
            ' Identify the used range in the sheet for rows
            Set objRange = objSheet.UsedRange
            
            ' Check if a valid range was found
            If Not objRange Is Nothing Then
                ' Limit the range to columns A to L
                Set objRange = objRange.Columns("A:L")
                
                ' Create a new sheet for the transposed data
                Set objTargetSheet = objWorkbook.Sheets.Add
                objTargetSheet.Name = "Transposed"
                
                ' Process the identified range
                For intRow = 1 To objRange.Rows.Count
                    For intCol = 1 To objRange.Columns.Count
                        Set objCell = objRange.Cells(intRow, intCol)
                        
                        ' Handling merged cells
                        If objCell.MergeCells Then
                            objTargetSheet.Cells(intCol, intRow).Value = objCell.MergeArea.Cells(1, 1).Value
                        Else
                            objTargetSheet.Cells(intCol, intRow).Value = objCell.Value
                        End If
                    Next
                Next
                
                ' Save and close the workbook as before
                objWorkbook.SaveAs "C:\xampp\htdocs\HTML\SSProcess\Extracted_FullSheet\" & objFSO.GetFileName(objFile.Path)
                objWorkbook.Close
            End If
        
        ' If a valid range was not found, report it in the log
        Else
            strErrorMessage = "No valid data range found in the file."
            objErrorLog.WriteLine "Error processing " & objFile.Name & ": " & strErrorMessage
        End If
        
        ' If an error occurred, write to the log
        If Err.Number <> 0 Then
            objErrorLog.WriteLine "Error processing " & objFile.Name & ": " & Err.Description
            Err.Clear
        End If
    End If
Next

' Cleanup
objErrorLog.Close
objExcel.Quit

Set objErrorLog = Nothing
Set objSheet = Nothing
Set objExcel = Nothing
Set objFSO = Nothing


PHP SCRIPT:
<?php
// Path to your VBScript
$vbscript = "C:\\xampp\\htdocs\\HTML\\SSProcess\\Scripts\\200-Full_Sheet_Extract.vbs";

// Execute the VBScript
$output = shell_exec("cscript.exe //Nologo " . $vbscript);

// Output the result if needed
echo $output;
?;


What I have tried:

i have tried a lot of methods to execute for example using exce, system, shell_exec , etc..
Posted
Updated 29-Mar-24 1:50am
v3

If this is a web application and your PHP code is the server-side code, your Office operations will not work. The Office applications are not supported through COM-interop in a non-desktop app environment.
 
Share this answer
 
You cannot run applications on the client computer at all for security reasons: if you could do that then anyone could, including the spammers, phishers, and malicious members of society - and the problem of ransomware would be much, much more prevalent for example.

It appears to work in dev because your web server and client are the same computer - so your server runs the script and you seem to see it working on the client because it's the same computer instead of a 1000Km away ...
 
Share this answer
 
Comments
Abed Al Rahman Hussien Balhawan 29-Mar-24 4:47am    
Hello the application runs in a server in xaamp file, the user uploads an excel file from him local PC to xaamp using a PHP script and then VBScript and python script are executed inside the server and after execution the PHP sends the file back to the user as a download.

please let me know if this is possible to achieve
OriginalGriff 29-Mar-24 5:21am    
Yes ... but ...
It needs a valid installation of Excel (and probably the whole of Office) on the web server, and that not normal, and unlikely to be popular with your website admin - each instance of Excel take a fair amount of system resources and you don't know how many instances the server will need to run at any time. Since it's a website that could be a considerable load on the web server and slug everything else.

A better solution would be to rewrite your scripts to do the job in PHP itself (since it runs on your server anyway) - there is an Excel library for PHP so it shouldn't be a major task.
How to Create and Modify Excel Spreadsheets in PHP[^]
As stated above, you cannot run a client side app (vbscript) with a server side app (php). An alternative approach is to use a server-side scripting language like Python or Node.js, which have libraries and modules specifically designed for working with Excel files. If I undertsand this correctly, your excel file will reside on the server, no hosting company will allow you to install office apps on their server.

I have done a small client/server example for you that will work as expected, you will however need to add a lot of security checks and validations in place for obvious reasons (do not use ChatGPT code as you did in your question) as it will never return teh expected results as you have experienced just now, you will probably need to read up more on the code as well regarding Javascript, Node and proper PHP executions -

Firstly, you will need to use a library that can interact with Excel files in Node which is node-xlsx, so install it. More on node-xlsx - Learn | node-xlsx
[^] -

npm install node-xlsx


Create a new JavaScript file which will run the script, I have called mine 'transposeExcel.js'. This file needs to be accessible by PHP so make sure your file structure allows this with proper named paths - PHP dirname[^]

JavaScript
const fs = require('fs');
const path = require('path');
const XLSX = require('node-xlsx');

//Change the path to your actual folder name when on a server...
const folderPath = 'C:\\xampp\\htdocs\\HTML\\SSProcess\\ExcelFiles';
const outputFolderPath = 'C:\\xampp\\htdocs\\HTML\\SSProcess\\Extracted_FullSheet';

fs.readdir(folderPath, (err, files) => {
  if (err) {
    console.error('Error reading directory:', err);
    return;
  }

  files.forEach(file => {
    const filePath = path.join(folderPath, file);
    const fileExtension = path.extname(file).toLowerCase();

    if (fileExtension === '.xlsx') {
      const workbook = XLSX.readFile(filePath);
      const sheetNames = workbook.SheetNames;

      //Find the sheet with the name containing "R" and having the highest numeric value...
      let maxNumber = -1;
      let sheetName = '';

      sheetNames.forEach(name => {
        const positionOfR = name.indexOf('R');
        if (positionOfR > 0) {
          const numericPart = name.substring(positionOfR + 1);
          if (isNumeric(numericPart)) {
            const currentNumber = parseInt(numericPart, 10);
            if (currentNumber > maxNumber) {
              maxNumber = currentNumber;
              sheetName = name;
            }
          }
        }
      });

      if (sheetName !== '') {
        const worksheet = workbook.Sheets[sheetName];
        const range = XLSX.utils.decode_range(worksheet['!ref']);

        //Limit the range to columns A to L...
        const limitedRange = {
          s: { r: range.s.r, c: 0 },
          e: { r: range.e.r, c: 11 }
        };

        //Create a new worksheet for the transposed data...
        const transposedWorksheet = XLSX.utils.aoa_to_sheet([]);

        //Process the identified range...
        for (let row = limitedRange.s.r; row <= limitedRange.e.r; row++) {
          for (let col = limitedRange.s.c; col <= limitedRange.e.c; col++) {
            const cell = worksheet[XLSX.utils.encode_cell({ r: row, c: col })];
            const mergeCells = XLSX.utils.decode_range(cell.r);

            if (mergeCells) {
              const mergedCell = worksheet[XLSX.utils.encode_cell(mergeCells.s)];
              XLSX.utils.sheet_add_aoa(transposedWorksheet, [[mergedCell.v]], { origin: { r: col, c: row } });
            } else {
              XLSX.utils.sheet_add_aoa(transposedWorksheet, [[cell.v]], { origin: { r: col, c: row } });
            }
          }
        }

        //Now add the transposed worksheet to your workbook...
        XLSX.utils.book_append_sheet(workbook, transposedWorksheet, 'Transposed');

        //Save your modified workbook...
        const outputFileName = path.join(outputFolderPath, file);
        XLSX.writeFile(workbook, outputFileName);
      } else {
        console.log(`No valid data range found in the file: ${file}`);
      }
    }
  });
});

function isNumeric(value) {
  return !isNaN(value) && isFinite(value);
}


To run the Node.js script in your PHP page, you'll need to execute the Node.js script using the 'exec()' function in PHP - PHP exec() function[^]

Security is key here... -
PHP
<?php
//Path to the Node.js executable, make sure you have the correct path set...
$nodePath = '/usr/bin/node';

//Path to the transposeExcel.js script...
$scriptPath = '/path/to/transposeExcel.js';

//Validate and sanitize ALL input paths...
$nodePath = filter_var($nodePath, FILTER_SANITIZE_STRING);
$scriptPath = filter_var($scriptPath, FILTER_SANITIZE_STRING);

//Check if the paths are set and valid...
if (empty($nodePath) || empty($scriptPath)) {
    echo 'Invalid paths provided.';
    exit;
}

//Check if the files exist and are executable...
if (!file_exists($nodePath) || !is_executable($nodePath)) {
    echo 'Node.js executable not found or not executable.';
    exit;
}

if (!file_exists($scriptPath) || !is_readable($scriptPath)) {
    echo 'Node.js script not found or not readable.';
    exit;
}

//Escape any user input or dynamic parts of the command...
$escapedScriptPath = escapeshellarg($scriptPath);

//Execute the Node.js script...
$command = $nodePath . ' ' . $escapedScriptPath;
$output = [];
$returnValue = 0;

exec($command, $output, $returnValue);

if ($returnValue !== 0) {
    echo 'Error executing Node.js script. Return value: ' . $returnValue . PHP_EOL;
    echo 'Output: ' . implode(PHP_EOL, $output);
} else {
    echo 'Node.js script executed successfully.';
}


I have not tested the code so you might get some minor errors to sort out but this will put you on the correct path.
 
Share this answer
 
v2
Comments
Abed Al Rahman Hussien Balhawan 29-Mar-24 10:14am    
Hello Andre, thank you for your response,I will try the script you provided and let you know,

please note that the purpose of my script is that users upload an excel file from his machine to the server path
'C:\\xampp\\htdocs\\HTML\\SSProcess\\ExcelFiles' by a button called "upload" in HTML scrip
bellow is part of code I did not include at the beginning of my question:

if(isset($_POST['upload'])){
$targetDir="C:\\SSProcess\\ExcelFiles\\";
$excel_path = $targetDir . basename ($_FILES["excelFile"][name]);

if (move_uploaded_file($_FILES["excelFile"]["tmp_name"], $excel_path)) {
echo "The file ". basename( $_FILES["excelFile"]["name"]). " has been uploaded.";
echo "file path = ", $excel_path, " .";

the idea is after the file is uploaded, the VBScript should be then executed all happening in the server side only, and yes office 365 are installed on the servers.

also, this is only one of 15 vbscripts to be executed, if there is an alternative way instead of changing the entire logic to jvscript I will be glad.

much thanks.
Andre Oosthuizen 30-Mar-24 5:36am    
You're welcome.

The upload of the file to your server is fine, the code I gave will then access that file and do the changes, whether it is 1 file or many.

I will still suggest that you change to JS as it will make life easier in the long run. If there are updates to excel, it might crash etc. Stay away from your current way, as Dave described above - "Office interop does not support re-entrancy, or more than one thread using the library at the same time. The code will crash and you'll get problem reports from the users that you will not be able to replicate."

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900