0
votes

I have been trying to write a PHP script to send SMS messages via a GSM modem connected to the server machine.

Below is the aforesaid PHP script.

<?php 
$device = "COM7";
exec("mode $device BAUD=9600 PARITY=n DATA=8");
$comport = fopen($device, "w");
fputs($comport,"AT+CMGF=1\n\r");
fputs($comport,"AT+cmgs=\"xxxxxxxxxx\"\n\r");
fputs($comport,"sms text\n\r");
fputs($comport,chr(26));
fclose($comport);
echo "done";  
?>

When I try to run the above code I get the following error;

Warning: fopen(COM7): failed to open stream: Permission denied in E:\wamp\www\sms\index.php on line 4

and

Warning: fclose() expects parameter 1 to be resource, boolean given in E:\wamp\www\sms\index.php on line 9

I have tried changing the user permission in windows to allow WAMP server full access, which WAMP server already had by default.

As a workaround I have tried using the DIO extension which gave a similar error when trying to open a port. DIO also gave an permission denied error.

It was suggested here in stackoverflow to use the physical address of the GSM modem instead of "COM7", I tried it didn't work. Another answer had suggested to add the www-data to the dialout group, but that solution was for Linux.

I tried writing a Java servlet as a workaround for this issue. The Java program runs as a stand alone file, but when its run as a servlet via Tomcat, it again gives an "Access Violation" error. I used RXTX library for the Java servlet.

So I am guessing this error is caused by lack of permission assigned to whoever is trying to access the com port via the server. (I get "SYSTEM" when I ran echo get_current_user(); from the above PHP script)

I am trying to find the root cause of this error. Your help is much appreciated.


Below is the Java SMS sender class which uses the RXTX Library.

import java.io.*;
import java.util.*;
import gnu.io.*;

public class SMSsender {
    static Enumeration portList;
    static CommPortIdentifier portId;
    static String messageString1 = "AT";
    static String messageString3 = "AT+CMGF=1";
    static String messageString4 = "AT+CMGS=\"+xxxxxxxxxx\"";

    static String messageString5 = "TESTY2";
    static SerialPort serialPort;
    static OutputStream outputStream;
    static InputStream inputStream;
    static char enter = 13;

    static char CTRLZ = 26;

    public void sendMessage(String[] args) throws InterruptedException {
        portList = CommPortIdentifier.getPortIdentifiers();

        while (portList.hasMoreElements()) {

            portId = (CommPortIdentifier) portList.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {

                if (portId.getName().equals("COM7")) {

                    try {
                        serialPort = (SerialPort) portId.open("COM7", 2000);
                    } catch (PortInUseException e) {
                        System.out.println("err");
                    }
                    try {
                        outputStream = serialPort.getOutputStream();
                        inputStream = serialPort.getInputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    try {
                        serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,

                                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                    } catch (UnsupportedCommOperationException e) {
                        e.printStackTrace();
                    }
                    try {

                        outputStream.write((messageString1 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        // outputStream.write((messageString2 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        outputStream.write((messageString3 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        outputStream.write((messageString4 + enter).getBytes());

                        Thread.sleep(100);
                        outputStream.flush();

                        outputStream.write((messageString5 + CTRLZ).getBytes());

                        outputStream.flush();
                        Thread.sleep(100);

                        System.out.println("step 1");
                        Thread.sleep(3000);

                        outputStream.close();
                        serialPort.close();
                        System.out.println("step 2");

                    } catch (IOException e) {
                        e.printStackTrace();
                        serialPort.close();
                    } finally {
                        serialPort.close();
                    }
                }
            }
        }
    }
}

Above code works when its run outside of the server as a stand alone application.

Following is the servlet code which invokes the above class to send an SMS.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class sendSMS extends HttpServlet {
       @Override
       public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        // Set the response MIME type of the response message
        response.setContentType("text/html");
        // Allocate a output writer to write the response message into the network socket
        PrintWriter out = response.getWriter();

        SMSsender obj = new SMSsender();
        try {
          obj.sendMessage(null);  
        }
        catch(Exception e)
        {
          out.println(e.getMessage());
        }
        finally {
        out.close();  // Always close the output writer
        }
    }
 }

When this servlet is run through Apache Tomcat, the server automatically closes with the following error in the log.

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000001cf32174465, pid=5828, tid=2276
#
# JRE version: Java(TM) SE Runtime Environment (10.0.2+13) (build 10.0.2+13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (10.0.2+13, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# C  [rxtxSerial.dll+0x4465]
#
# No core dump will be written. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
1
Don't post errors as screenshots.Spoody
Hi. I am new here. I wanted to show what the exact error was.Chin. Udara
Welcome to Stackoverflow then. You should always post code and errors as text in the question itself and not as an image. Also check How to AskSpoody
If you're tagging it with java and talking about a problem with a java program, you should post a minimal reproducible example in Java and include the exact error message.Erwin Bolwidt
I added the java code along with the error I got. Thank youChin. Udara

1 Answers

1
votes

I was able to solve the issue.

Apparently, windows no longer allows to communicate with serial ports via virtual file names. In the case of PHP, I was trying to get in-touch with the com port via fopen("com7"). So this method is no longer viable it seems. This is according to David Gibson. View Source Here . I would love to read more on this if I could find the original source though.

According to David Gibson's post, PHP extensions like DIO is not very stable in the Windows environment. So I stopped trying to find a solution to my PHP code.

Now to the Java workaround

Earlier I was trying to use the RXTX java library. Although the code worked as a standalone application, it failed with an "Access Violation" error when run via tomcat. I wonder if RXTX is still in active development.

Anyhow I tired out the platform independent solution jSerialComm. Pretty amazing, it doesn't require any DLLs or any other native libraries.

I was finally able to send a SMS via a servlet thanks to this awesome, easy to use library. I have posted my working Java code below for your reference.

I hope this will help someone who is facing the same problem! Cheers!

And thanks to Mehdi, Erwin and Sanguinary for the guidance given with regards to using this amazing Stackoverflow platform and of course to the developers!

Note: This code below is messy and not optimised. This code is for reference only.

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
//import java.io.InputStream;
import java.util.Scanner;
import com.fazecast.jSerialComm.*;

public class sendSMS extends HttpServlet {
    SerialPort ubxPort;

    static String messageString1 = "AT";
    static String messageString2 = "AT+CMGF=1"; 
    static String messageString3 = "AT+CMGS=\"+xxxxxxxxxx\"";
    static String messageString4 = "TESTY2";
    static char enter = 13;
    static char CTRLZ = 26;


   @Override
   public void doGet(HttpServletRequest request, HttpServletResponse response)
         throws IOException, ServletException {

      // Set the response MIME type of the response message
      response.setContentType("text/html");
      // Allocate a output writer to write the response message into the network socket
      PrintWriter out = response.getWriter();


      try {

          ubxPort = SerialPort.getCommPort("com7");
          boolean openedSuccessfully = ubxPort.openPort();
          out.println("h1<br>");
          if(openedSuccessfully)
          {
            out.println("Port Opened<br>");
            byte[] buffer = (messageString1 + enter).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("1 sent<br>");

            InputStream in = ubxPort.getInputStream();
            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

            buffer = (messageString2 + enter).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("2 sent<br>");

            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

            buffer = (messageString3 + enter).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("3 sent<br>");

            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

            buffer = (messageString4 + CTRLZ).getBytes();
            ubxPort.writeBytes(buffer, buffer.length);
            out.println("4 sent<br>");

            try
            {
               for (int j = 0; j < 1000; ++j)
                  System.out.print((char)in.read());
               in.close();
            } catch (Exception e) { e.printStackTrace(); }

          }

      }
      catch(Exception e)
      {
          out.println("here3");
          out.println(e.getMessage());
      }
      finally {
          ubxPort.closePort();
          out.println("here4");
         out.close();  // Always close the output writer
      }
   }
}