civicrm/cv

"Failed to locate civicrm.settings.php" using example cv wrapper function fails

artfulrobot opened this issue · 1 comments

I'm logging this here for the sake of others being able to find/recognise the issue.

Symptom

My script:

#!/usr/bin/env php
<?php
function cv(...) // From the latest README.

// This call fails
eval(cv('php:boot', 'phpcode'));

// This succeeds:
eval(`cv php:boot`);

The error is:

[Exception]

Failed to locate civicrm.settings.php. By default, this tool searches the parent directories for a standard CMS (Drupal, WordPress, etal) and standard civicrm.settings.php. Symlinks andmul
tisite configurations may interfere. To customize, set variable CIVICRM_SETTINGS to point to the preferred civicrm.settings.php.

The environment is D7, CiviCRM 5.15.1, PHP 7.3 (in a VirtualBox).

Problem

The problem seems to be that the cv() function assumes that the script itself lives inside the CiviCRM webroot.

If your script is somewhere else (e.g. ~/bin/myscript) then because the proc_open call passes in __DIR__ the process runs from your ~/bin dir, and of course then it can't find CiviCRM.

Fix ideas

We could document that the script MUST be in the CiviCRM webroot to work.

in which case I think we should add some guards against it being run over http, e.g. I regularly use this at the top of cli scripts:

if (php_sapi_name() !== 'cli') {
  // Fail with 404 if not called from CLI.
  if (isset($_SERVER['HTTP_PROTOCOL'])) {
    header("$_SERVER[HTTP_PROTOCOL] 404 Not Found");
  }
  exit;
}

Or we could make it an option to the demo cv function, e.g.

/**
 * @param string $dir
 *      script|cwd|/some/other/directory
 */
function cv($cmd, $decode = 'json', $dir = 'script') {
  if ($dir === 'script') {
    $dir = __DIR__;
  }
  elseif ($dir === 'cwd') {
    $dir = getcwd();
  }
}

That feels messy though.

How about using a constant: we could include this at the top:

// You will need to change this, e.g. to getcwd() if your script does not
// live inside your webroot.
define('CV_WORKING_DIR', __DIR__);

It would be nice to have the ability to add aliases and run commands on multiple sites at once :)