How can I include php codesniffer and mess detector ruleset or report?

Hi all ,
I am new in using sonar ,trying find the way to include custom rule in sonar scanner analysis here is some queries I want to know

  1. How to include PHP code sniffer and mess detector ruleset , wanted to know step ?
  2. If Sonar scanner can not incorporate rule then how can I send the report of code sniffer and mess detector , I want the to know the example format and steps to send report through
    Any guidance is welcome
    Thanks in advance
    Note : My sonar version : Enterprise Edition Version 8.7.1

Hey @Shashank_Gupta1 ,

Welcome to the community!

The answer to both your questions is: you need to transform the output of the tools to our generic external issue import JSON format ( Generic Issue Import Format | SonarQube Docs ).
Both tools seem to support outputting the report to either XML or JSON files. So one way of doing this is to save the output to such a file, and than create a custom script that will parse the output and transform it to the SonarQube generic external issues format.
When you get the output in the correct format, all is left to do is to add the sonar.externalIssuesReportPaths pointing to the correct file to your analysis properties.

We have recently added specific support for PHPStan and Psalm (SonarCloud can load issues from PHPStan and Psalm). For tools for which we have specific support, the process is easier because the report transformation step becomes unnecessary.
We will consider if we want to support PHPCS and PHPMD in the future.


Thanks for your reply , at the moment I guess code sniffer report can only be generated and submitted by the report format you provide , this the only way for sonarqube set version 8.7 , So may I ask you if you know just in case any tool which create codesniffer report in generic sonarqube report format ? We wanna integrate phpcs report generate and submit according to Adobe commerce (Magento2) coding standards.
Currently I am able to generate this format file

  "totals": {
    "errors": 0,
    "warnings": 2,
    "fixable": 0
  "files": {
    "filepath": {
      "errors": 0,
      "warnings": 2,
      "messages": [
          "message": "Tag @package MUST NOT be used.",
          "source": "Magento2.Commenting.ClassAndInterfacePHPDocFormatting.ForbiddenTags",
          "severity": 5,
          "fixable": false,
          "type": "WARNING",
          "line": 14,
          "column": 4
          "message": "Class description must contain meaningful information beyond what its name provides or be removed.",
          "source": "Magento2.Commenting.ClassAndInterfacePHPDocFormatting.InvalidDescription",
          "severity": 5,
          "fixable": false,
          "type": "WARNING",
          "line": 16,
          "column": 1


Hey @Shashank_Gupta1 ,

Yes, you’ll need to first generate the PHP_CodeSniffer report, transform it to the SonarQube generic external issue format, and then load it sonar.externalIssuesReportPaths when scanning.

Unfortunately, I do not know of any existing tool that does the transformation from PHP_CodeSniffer format to the SonarQube format. However, with a scripting language of your choice, this shouldn’t be too difficult of a task. The PHP_CodeSniffer report has already the required fields. You’ll just need to loop over the PHP_CodeSniffer report JSON and map it to the JSON structure expected by SonarQube . Check the import section in the documentation of the SonarQube format to see which fields are required, and which are optional.

Here is how such a transformation script could look in python. This is untested and potentially incomplete, but maybe a starting point.

import json

def to_sq_issue(filePath, PhpCsMessage):
    return {
        "engineId": "PHPCS",
        "ruleId": PhpCsMessage["source"],
        "severity": "INFO",
        "type": "BUG",
        "primaryLocation": {
            "message": PhpCsMessage["message"],
            "filePath": filePath,
            "textRange": {
                "startLine": PhpCsMessage["line"],
                "startColumn": PhpCsMessage["column"]

with open("phpcs-report.json") as jsonFile:
    jsonObject = json.load(jsonFile)

result = {"issues": []}
for filePath in jsonObject["files"]:
    for PhpCsMessage in jsonObject["files"][filePath]["messages"]:
        result["issues"].append(to_sq_issue(filePath, PhpCsMessage))

with open("sq-report.json", "w") as jsonFile:
    json.dump(result, jsonFile)

Thanks for the reply , But I receive following error of the while using the output sq-report.json

> java.lang.IllegalArgumentException: 1 is not a valid line offset for pointer. File app/code/vendor/Module/Model/UrlBuilder.php has 0 character(s) at line 35
> 	at org.sonar.api.utils.Preconditions.checkArgument(
> 	at org.sonar.api.batch.fs.internal.DefaultInputFile.checkValid(
> 	at org.sonar.api.batch.fs.internal.DefaultInputFile.newPointer(
> 	at org.sonar.scanner.externalissue.ExternalIssueImporter.fillLocation(
> 	at org.sonar.scanner.externalissue.ExternalIssueImporter.importIssue(
> 	at org.sonar.scanner.externalissue.ExternalIssueImporter.execute(
> 	at org.sonar.scanner.externalissue.ExternalIssuesImportSensor.execute(
> 	at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(
> 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(
> 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(
> 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(
> 	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(
> 	at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(
> 	at org.sonar.core.platform.ComponentContainer.startComponents(
> 	at org.sonar.core.platform.ComponentContainer.execute(
> 	at org.sonar.scanner.scan.ProjectScanContainer.scan(
> 	at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(
> 	at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(
> 	at org.sonar.core.platform.ComponentContainer.startComponents(
> 	at org.sonar.core.platform.ComponentContainer.execute(
> 	at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(
> 	at org.sonar.core.platform.ComponentContainer.startComponents(
> 	at org.sonar.core.platform.ComponentContainer.execute(
> 	at org.sonar.batch.bootstrapper.Batch.doExecute(
> 	at org.sonar.batch.bootstrapper.Batch.execute(
> 	at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(
> 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
> 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
> 	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
> 	at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(
> 	at com.sun.proxy.$Proxy0.execute(Unknown Source)
> 	at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(
> 	at org.sonarsource.scanner.api.EmbeddedScanner.execute(
> 	at org.sonarsource.scanner.cli.Main.execute(
> 	at org.sonarsource.scanner.cli.Main.execute(
> 	at org.sonarsource.scanner.cli.Main.main(

I am wondering if you already found the solution for this ?

What the error is saying is that PHP_CodeSniffer is reporting an issue at a location (line+column) in which SonarQube sees no content.

It is difficult to say what the exact reason and a potential solution is without seeing the content of app/code/vendor/Module/Model/UrlBuilder.php and what PHP_CodeSniffer is reporting in that file. Can you share both of these with me? In case the content needs to be kept private, we can start a private thread.

Also: when sharing code or logs in your posts, please format using the “Preformatted text” function in the forum post editor. This makes it much easier to read.

Yes, Please share the thread , Additional information we are using SonarQube 8.7.1 enterprise version.

To resolve this thread:

The problem @Shashank_Gupta1 encountered in his last post when importing a PHP_CodeSniffer report transformed to the SonarQube generic external issues report format (with the example script given above), was because PHP_CodeSniffer and SonarQube count columns differently: for SonarQube they start at 0 while for PHP_CodeSniffer they start at 1. To be safe, it is best to leave the startColumn out while transforming, and have the issue raised on the whole line.

As we did for Psalm and PHPStan, we might consider in the future adding a feature to import PHP_CodeSniffer reports without having to transform them first. A good way of showing that there is interest for this is to post it to Suggest new features - SonarSource Community section of this forum and vote for it.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.