diff --git a/.github/workflows/packaging.yml b/.github/workflows/packaging.yml
index b06cb8484..014f84159 100644
--- a/.github/workflows/packaging.yml
+++ b/.github/workflows/packaging.yml
@@ -11,126 +11,174 @@ on:
jobs:
debian:
name: Debian package
- runs-on: ubuntu-latest
+ runs-on: ubuntu-22.04
+ env:
+ KEY_ID: ${{ vars.KALKUN_GITHUB_WORKFLOW_PACKAGER_KEY_FINGERPRINT }}
+ DPUT_CF: /home/runner/dput.cf
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install required packages
run: |
sudo apt-get update
- sudo apt-get install -y git-buildpackage build-essential dh-apache2 pkg-php-tools phpab php-xdebug
+ sudo apt-get install -y git-buildpackage build-essential equivs
+
+ # For kalkun source build dependency
+ sudo apt-get install -y pkg-php-tools dh-apache2
+
+ # For sphinxcontrib-phpdomain source build dependency
+ sudo apt-get install -y dh-python
+
+ # For backportpackage
+ sudo apt-get install -y ubuntu-dev-tools
+
cd ~
- # These need to be more recent than the ones shipped in ubuntu focal (to build the dependencies)
- # We need these versions to build the dependencies. The previous ones don't work well with php 7.4 that is in ubuntu focal.
- wget http://ftp.us.debian.org/debian/pool/main/p/php-zeta-console-tools/php-zeta-console-tools_1.7.2-2_all.deb
- wget http://ftp.us.debian.org/debian/pool/main/p/phpab/phpab_1.26.0-1_all.deb
- # There is this crash with dh_phpcomposer on ubuntu focal
- # Non-static method Pkgtools\Base\Overrides::override() cannot be called statically in /usr/share/php/pkgtools/base/dependencies.php:45
- # So we update pkg-php-tools to version 1.40 (focal has 1.38)
- wget http://ftp.us.debian.org/debian/pool/main/p/pkg-php-tools/pkg-php-tools_1.40_all.deb
- # Get php-random-compat (build dependency on >= 2.0.20)
- wget http://mirrors.kernel.org/ubuntu/pool/universe/p/php-random-compat/php-random-compat_2.0.21-1_all.deb
- # Install the packages
- sudo dpkg -i php-zeta-console-tools_1.7.2-2_all.deb phpab_1.26.0-1_all.deb pkg-php-tools_1.40_all.deb php-random-compat_2.0.21-1_all.deb
+ - name: Import GPG key & related stuff
+ env:
+ PUB_KEY: ${{ secrets.KALKUN_GITHUB_WORKFLOW_PACKAGER_KEY_PRIVATE }}
+ PUB_KEY_PASS: ${{ secrets.KALKUN_GITHUB_WORKFLOW_PACKAGER_KEY_PASSPHRASE }}
+ KEYGRIP: ${{ secrets.KALKUN_GITHUB_WORKFLOW_PACKAGER_KEY_KEYGRIP }}
+ run: |
+ # As per: https://stackoverflow.com/a/55032706/15401262
+ export GPG_TTY=$(tty)
+
+ # Import private key
+ echo "$PUB_KEY" | gpg --batch --import
+
+ # List secret keys
+ gpg --list-secret-keys --with-keygrip
+
+ # Preset Password
+ echo "allow-preset-passphrase" >> ~/.gnupg/gpg-agent.conf
+ gpg-connect-agent reloadagent /bye
+ echo "$PUB_KEY_PASS" | /usr/lib/gnupg/gpg-preset-passphrase --preset "$KEYGRIP"
+ - name: Configure dput
+ run: |
+ sed "s/%LAUNCHPAD_USER_NAME%/${{ vars.LAUNCHPAD_USER_NAME }}/" utils/launchpad/dput.cf.in > $DPUT_CF
- name: Set env
run: |
- echo "LAST_COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- echo "LAST_COMMIT_DATE=$(git log -1 --date=format:%Y%m%d --format=%cd)" >> $GITHUB_ENV
- echo "KALKUN_VERSION=$(grep kalkun_version application/config/kalkun_settings.php | cut -d "'" -f 4)" >> $GITHUB_ENV
- echo "DEBEMAIL=none@domain.tld" >> $GITHUB_ENV
- echo "DEBFULLNAME='Github Actions Deb Builder for Kalkun'" >> $GITHUB_ENV
- - name: Build dependencies
+ echo "DEBEMAIL=packager@kalkun.invalid" >> $GITHUB_ENV
+ echo "DEBFULLNAME=Kalkun github workflow packager" >> $GITHUB_ENV
+ if [[ "$(git tag --points-at ${GIT_BRANCH})" != "" ]]; then \
+ echo "DPUT_UPLOAD_SERVER=kalkun-releases" >> $GITHUB_ENV
+ else \
+ echo "DPUT_UPLOAD_SERVER=kalkun-snapshots" >> $GITHUB_ENV
+ fi
+ - name: Git config user
run: |
- set -x
- # get the packages from debian salsa servers as they have not entered Debian yet
-
- mkdir -p ~/deps
- cd ~/deps
- gbp clone https://salsa.debian.org/php-team/pear/php-codeigniter-framework
- gbp clone https://salsa.debian.org/php-team/pear/php-datto-json-rpc
- gbp clone https://salsa.debian.org/php-team/pear/php-datto-json-rpc-http
- gbp clone https://salsa.debian.org/php-team/pear/php-giggsey-locale
- gbp clone https://salsa.debian.org/php-team/pear/php-giggsey-libphonenumber
- gbp clone https://salsa.debian.org/php-team/pear/php-kissifrot-php-ixr
- gbp clone https://salsa.debian.org/php-team/pear/php-league-csv
-
- # Install some dependencies to be able to build the packages (for php-giggsey-locale & php-league-csv)
- sudo apt-get install -y phpunit php-symfony-console php-symfony-filesystem
- sudo apt-get install -y php-curl php-xdebug
-
- # First build php-giggsey-locale because it is a dependency to build php-giggsey-libphonenumber
- cd php-giggsey-locale ; \
- gbp export-orig ; \
- sed -i -e "s/debhelper-compat (= 13)/debhelper-compat (= 12)/" debian/control ; \
- dpkg-buildpackage -d ; \
- cd ~/deps ; \
- # Install php-giggsey-locale
- sudo apt-get install ./php-giggsey-locale*.deb
-
- # We apply a change with sed:
- # - depend on debhelper 12 (because ubuntu focal has only debhelper 12)
- for dir in $(find -type d -maxdepth 1 -mindepth 1); do \
- cd $dir; \
- gbp export-orig ; \
- sed -i -e "s/debhelper-compat (= 13)/debhelper-compat (= 12)/" debian/control ; \
- dpkg-buildpackage -d ; \
- cd ~/deps ; \
- done
- - name: Build kalkun packages
+ git config user.name "$DEBFULLNAME"
+ git config user.email "$DEBEMAIL"
+ - name: Build kalkun build-dependencies
run: |
set -x
- # Download the only the debian folder from debian salsa servers to be able to build kalkun
- # This adds only the debian folder to $GITHUB_REF_NAME to be able to build the packages
- git remote add debian https://salsa.debian.org/bastif/kalkun.git
- git fetch debian
- git checkout -b debian_branch debian/master
- git checkout $GITHUB_REF_NAME
- git checkout debian_branch -- debian
- git status
+ # Don't error out to not fail the github job if a dsc is not available anymore.
+ set +e
- if [[ "$(git tag --points-at ${GIT_BRANCH})" != "" ]]; then \
- KALKUN_VERSION="$(git tag --points-at ${GIT_BRANCH} | sed "s/^v//")" ; \
- DEB_VERSION=$(echo ${KALKUN_VERSION} | sed -e "s/-/~/g")-1 ; \
- rm debian/changelog
- dch --package kalkun --newversion="$DEB_VERSION" --create $DEB_VERSION ; \
- gbp export-orig --upstream-tag=$(git tag --points-at ${GIT_BRANCH}) --compression=xz ; \
- else \
- DEB_VERSION=$(echo $KALKUN_VERSION | sed -e "s/-/~/g")~${LAST_COMMIT_DATE} ; \
- gbp dch --new-version="$DEB_VERSION" --snapshot --ignore-branch ; \
- # Append debian version to version number ; \
- sed -i -e "1s/)/-1)/" debian/changelog ; \
- gbp export-orig --upstream-tree=BRANCH --upstream-branch=$(git rev-parse --abbrev-ref HEAD) --compression=xz ; \
- fi
+ # Upload somes dependencies to the "kalkun-build-deps" PPA for focal
+ # debhelper13 for focal (from focal-backports)
+ ./utils/upload_build_deps_to_ppa.sh -d focal http://archive.ubuntu.com/ubuntu/pool/main/d/debhelper/debhelper_13.6ubuntu1~bpo20.04.1.dsc
+
+ # pkg-php-tools for focal (from jammy) - Don't use it, because it requires the dependencies to conform to the new way php-pkg-tools work, and in focal, the packages don't support that.
+ # ./utils/upload_build_deps_to_ppa.sh -d focal http://archive.ubuntu.com/ubuntu/pool/main/p/pkg-php-tools/pkg-php-tools_1.42build1.dsc
+
+ # Error out again
+ set -e
+
+ REPOS_TO_BUILD=()
+
+ # Order matters so that build dependencies are installed before the packages requiring them.
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-datto-json-rpc")
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-datto-json-rpc-http")
+
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-giggsey-locale")
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-giggsey-libphonenumber")
- # depend on debhelper 12 (because ubuntu focal has only debhelper 12)
- sed -i -e "s/debhelper-compat (= 13)/debhelper-compat (= 12)/" debian/control
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-econea-nusoap")
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-kissifrot-php-ixr")
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-league-csv")
+
+ REPOS_TO_BUILD+=("https://salsa.debian.org/bastif/sphinxcontrib-phpdomain")
+ REPOS_TO_BUILD+=("https://salsa.debian.org/php-team/pear/php-codeigniter-framework")
+
+ for repo in "${REPOS_TO_BUILD[@]}"; do
+ ./utils/upload_kalkun_deps_to_ppa.sh -r "$repo" -d "$(ubuntu-distro-info --supported)" -h "${DPUT_UPLOAD_SERVER}"
+ done
+
+ - name: Build kalkun
+ run: |
+ set -x
+
+ ./utils/upload_kalkun_deps_to_ppa.sh -r "kalkun" -d "$(ubuntu-distro-info --supported)" -h "${DPUT_UPLOAD_SERVER}"
- dpkg-buildpackage -d
- name: Copy source & binary packages, and dependencies
if: always()
run: |
set -x
mkdir -p ~/Kalkun_${GITHUB_REF_NAME}_debianBundle
- dcmd mv ../*.changes ~/Kalkun_${GITHUB_REF_NAME}_debianBundle
- cp ~/deps/*.deb ~/Kalkun_${GITHUB_REF_NAME}_debianBundle
+ # Copy kalkun source & binary packages
+ dcmd mv ~/build_products/kalkun*.changes ~/Kalkun_${GITHUB_REF_NAME}_debianBundle
+ # Copy binary packages of dependencies
+ dcmd --deb mv ~/build_products/*.changes ~/Kalkun_${GITHUB_REF_NAME}_debianBundle
cd ~ && tar -cvf Kalkun_${GITHUB_REF_NAME}_debianBundle.tar Kalkun_${GITHUB_REF_NAME}_debianBundle
echo "my_home=$HOME" >> $GITHUB_ENV
- name: Archive artifacts
if: always()
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: Debian packages (source & binary)
path: ~/Kalkun_${{ github.ref_name }}_debianBundle/*
if-no-files-found: ignore
- - name: Release
- uses: softprops/action-gh-release@v1
- if: startsWith(github.ref, 'refs/tags/')
+ - name: Archive artifacts
+ if: always()
+ uses: actions/upload-artifact@v3
with:
- files: |
- ${{ env.my_home }}/Kalkun_${{ github.ref_name }}_debianBundle.tar
+ name: Debian packages (source & binary) tarball
+ path: ~/Kalkun_${{ github.ref_name }}_debianBundle.tar
+ if-no-files-found: ignore
+
+ required_php_versions:
+ name: Get PHP versions to pack for
+ runs-on: ubuntu-latest
+ outputs:
+ php_versions: ${{ steps.php_ver_step.outputs.PHP_VERSIONS }}
+ php_versions_matrix: ${{ steps.php_ver_step.outputs.PHP_VERSIONS_matrix }}
+ steps:
+ - name: Install required packages
+ run: |
+ if ! command -v jq; then sudo apt-get update && sudo apt-get install -y jq; fi
+ - name: Build PHP_VERSIONS array & PHP_VERSIONS_matrix
+ id: php_ver_step
+ run: |
+ set -x
+
+ # Set array that will store the PHP versions for which we create a package.
+ PHP_VERSIONS=()
+
+ # Start with 7.4.30 since this is for the DEMO we publish on sourceforge.
+ PHP_VERSIONS+=("7.4.30")
+
+ # Get all released php versions above 5.6 (in the format X.Y)
+ for upstream_ver in $(curl https://www.php.net/releases/?json | jq -r '.[].version' | cut -f -2 -d .); do
+ major=$(cut -f 1 -d . <<< "$upstream_ver")
+ for minor in {0..20}; do
+ if dpkg --compare-versions ${major}.$minor le $upstream_ver && dpkg --compare-versions ${major}.$minor ge 5.6; then
+ PHP_VERSIONS+=("${major}.$minor")
+ fi
+ done
+ done
+
+ PHP_VERSIONS_matrix=$(sed 's/\ /", "/g' <<< [\"${PHP_VERSIONS[*]}\"])
+
+ echo "PHP_VERSIONS=${PHP_VERSIONS[*]}" >> "$GITHUB_OUTPUT"
+ echo "PHP_VERSIONS_matrix=$PHP_VERSIONS_matrix" >> "$GITHUB_OUTPUT"
+
+ echo "PHP_VERSIONS=${PHP_VERSIONS[*]}"
+ echo "PHP_VERSIONS_matrix=$PHP_VERSIONS_matrix"
+
prebuilt:
- name: Prebuilt packages by PHP version
+ name: Prebuild packages by PHP version
+ needs: [ required_php_versions ]
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -141,82 +189,101 @@ jobs:
dev: no
php_version: "7.4"
php_extensions: ctype curl hash intl json mbstring session
- - name: Install required packages
- run: |
- if ! command -v jq; then sudo apt-get update && sudo apt-get install -y jq; fi
- name: Build prebuilt packages with Composer dependencies
+ env:
+ PHP_VERSIONS: ${{needs.required_php_versions.outputs.php_versions}}
run: |
set -x
+
git fetch --prune --unshallow --tags
- # Start with 7.1.24 since this is for the DEMO we publish on sourceforge.
- ./utils/build_single_dist.sh 7.1.24
- # They build for all versions.
- ./utils/build_single_dist.sh 5.6
- ./utils/build_single_dist.sh 7.0
- ./utils/build_single_dist.sh 7.2
- ./utils/build_single_dist.sh 7.3
- ./utils/build_single_dist.sh 7.4
- ./utils/build_single_dist.sh 8.0
- ./utils/build_single_dist.sh 8.1
+
+ for version in $PHP_VERSIONS; do
+ ./utils/build_single_dist.sh "$version"
+ done
+
ls dist
- - name: Archive artifacts for PHP 5.6
- if: always()
- uses: actions/upload-artifact@v2
- with:
- name: Prebuilt package for PHP 5.6
- path: 'dist/*forPHP5.6*'
- if-no-files-found: ignore
- - name: Archive artifacts for PHP 7.0
- if: always()
- uses: actions/upload-artifact@v2
- with:
- name: Prebuilt package for PHP 7.0
- path: 'dist/*forPHP7.0*'
- if-no-files-found: ignore
- - name: Archive artifacts for PHP 7.1.24
- if: always()
- uses: actions/upload-artifact@v2
- with:
- name: Prebuilt package for PHP 7.1.24
- path: 'dist/*forPHP7.1.24*'
- if-no-files-found: ignore
- - name: Archive artifacts for PHP 7.2
+ - name: Archive artifacts (all prebuilt packages)
if: always()
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
- name: Prebuilt package for PHP 7.2
- path: 'dist/*forPHP7.2*'
+ name: Prebuilt packages (all)
+ path: 'dist/'
if-no-files-found: ignore
- - name: Archive artifacts for PHP 7.3
+
+ individual_artifacts:
+ name: Create artifacts for ${{ matrix.version }}
+ needs: [ prebuilt, required_php_versions ]
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ #version: ["5.6", "7.0", "7.4.30"]
+ version: ${{fromJson(needs.required_php_versions.outputs.php_versions_matrix)}}
+ steps:
+ - name: Download artifact of 'prebuilt packages'
if: always()
- uses: actions/upload-artifact@v2
+ uses: actions/download-artifact@v3
with:
- name: Prebuilt package for PHP 7.3
- path: 'dist/*forPHP7.3*'
- if-no-files-found: ignore
- - name: Archive artifacts for PHP 7.4
+ name: Prebuilt packages (all)
+ path: 'dist/'
+ - name: Display structure of downloaded files
+ run: ls -R
+ working-directory: 'dist'
+ - name: Archive artifacts for ${{ matrix.version }}
if: always()
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
- name: Prebuilt package for PHP 7.4
- path: 'dist/*forPHP7.4*'
+ name: Prebuilt package for PHP ${{ matrix.version }}
+ path: 'dist/*forPHP${{ matrix.version }}.[tz]*'
if-no-files-found: ignore
- - name: Archive artifacts for PHP 8.0
- if: always()
- uses: actions/upload-artifact@v2
+
+ release:
+ name: Create release and add packages
+ needs: [ prebuilt, debian ]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download artifact of 'prebuilt packages'
+ if: startsWith(github.ref, 'refs/tags/')
+ uses: actions/download-artifact@v3
with:
- name: Prebuilt package for PHP 8.0
- path: 'dist/*forPHP8.0*'
- if-no-files-found: ignore
- - name: Archive artifacts for PHP 8.1
- if: always()
- uses: actions/upload-artifact@v2
+ name: Prebuilt packages (all)
+ path: 'dist/'
+ - name: Download artifact of 'Debian packages'
+ if: startsWith(github.ref, 'refs/tags/')
+ uses: actions/download-artifact@v3
with:
- name: Prebuilt package for PHP 8.1
- path: 'dist/*forPHP8.1*'
- if-no-files-found: ignore
+ name: Debian packages (source & binary) tarball
+ path: 'dist/'
+ - name: Display structure of downloaded files
+ if: startsWith(github.ref, 'refs/tags/')
+ run: ls -R
+ working-directory: 'dist'
+ - name: Check if is prerelease
+ if: startsWith(github.ref, 'refs/tags/')
+ run: |
+ if [[ "$GITHUB_REF_NAME" =~ alpha|beta|rc ]]; then
+ echo "is_prerelease=true" >> $GITHUB_ENV
+ else
+ echo "is_prerelease=false" >> $GITHUB_ENV
+ fi
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
- files: "dist/*"
+ fail_on_unmatched_files: true
+ prerelease: ${{ env.is_prerelease }}
+ files: |
+ dist/*
+
+ delete_artifacts:
+ needs: [ individual_artifacts, release ]
+ name: Delete temporary artifact
+ runs-on: ubuntu-latest
+ steps:
+ - uses: geekyeggo/delete-artifact@v2
+ with:
+ name: Prebuilt packages (all)
+ failOnError: false
+ - uses: geekyeggo/delete-artifact@v2
+ with:
+ name: Debian packages (source & binary) tarball
+ failOnError: false
diff --git a/.gitignore b/.gitignore
index fd29b7bae..09424aaf2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,5 @@ application/config/database.php
/vendor/
.php-cs-fixer.cache
/dist
+
+/utils/launchpad/dput.cf
diff --git a/application/config/kalkun_settings.php b/application/config/kalkun_settings.php
index c5ba7cf23..5b1179663 100644
--- a/application/config/kalkun_settings.php
+++ b/application/config/kalkun_settings.php
@@ -11,9 +11,9 @@
| https://github.com/kalkun-sms/Kalkun/wiki/Developing#Version-numbering-guidelines
|
*/
-$config['kalkun_version'] = '0.8.0';
+$config['kalkun_version'] = '0.8.1-beta-1';
$config['kalkun_codename'] = '-';
-$config['kalkun_release_date'] = '2022-10-14';
+$config['kalkun_release_date'] = '-';
/*
|--------------------------------------------------------------------------
diff --git a/application/controllers/Kalkun.php b/application/controllers/Kalkun.php
index 9c8a1c234..51f62b5e9 100644
--- a/application/controllers/Kalkun.php
+++ b/application/controllers/Kalkun.php
@@ -233,7 +233,7 @@ function unread_count()
function add_folder()
{
$this->Kalkun_model->add_folder();
- redirect($this->input->post('source_url'));
+ redirect($this->input->post('source_url') !== NULL ? $this->input->post('source_url') : '');
}
// --------------------------------------------------------------------
@@ -376,6 +376,32 @@ function phone_number_validation()
echo json_encode($result);
}
+ // --------------------------------------------------------------------
+
+ /**
+ * Check multiple phone number validity
+ *
+ * returns a json string used by jquery validation plugin
+ * "true" if all phone numbers are valid
+ * "an error message with the faulty number" if not
+ */
+ function phone_number_validation_multiple()
+ {
+ $tmp_dest = explode(',', $this->input->get_post('phone'));
+ foreach ($tmp_dest as $key => $val)
+ {
+ $result = is_phone_number_valid($val, $this->input->get_post('region'));
+ if ($result !== TRUE)
+ {
+ header('Content-type: application/json');
+ echo json_encode($result.' ('.trim($val).')');
+ return;
+ }
+ }
+ header('Content-type: application/json');
+ echo json_encode('true');
+ }
+
function get_csrf_hash()
{
header('Content-type: application/json');
diff --git a/application/controllers/Messages.php b/application/controllers/Messages.php
index 217d80e3c..4d82829fc 100644
--- a/application/controllers/Messages.php
+++ b/application/controllers/Messages.php
@@ -352,7 +352,7 @@ function compose_process()
$tmp_dest = explode(',', $this->input->post('manualvalue'));
foreach ($tmp_dest as $key => $tmp)
{
- $this->_phone_number_validation($this->input->post('manualvalue'));
+ $this->_phone_number_validation($tmp);
$dest[$key] = phone_format_e164($tmp);
}
break;
diff --git a/application/core/MY_Lang.php b/application/core/MY_Lang.php
index 5ad3c2b9d..b9ca9f7b1 100644
--- a/application/core/MY_Lang.php
+++ b/application/core/MY_Lang.php
@@ -35,6 +35,7 @@ class MY_Lang extends MX_Lang {
'hungarian' => 'hu',
'indonesian' => 'in',
'italian' => 'it',
+ 'norwegian' => 'no',
'polish' => 'pl',
'portuguese' => 'pt',
'russian' => 'ru',
@@ -101,8 +102,7 @@ public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE
}
if ($alt_path !== '')
{
- $alt_path .= 'language/'.$this->idiom.'/'.$langfile;
- if (file_exists($alt_path))
+ if (file_exists($alt_path.'language/'.$this->idiom.'/'.$langfile))
{
$found = TRUE;
}
@@ -123,7 +123,7 @@ public function load($langfile, $idiom = '', $return = FALSE, $add_suffix = TRUE
// Fallback to english if language file is not found
if ( ! $found)
{
- log_message('error', "language file ${langfile} not found. Falling back to english.");
+ log_message('error', "language file {$langfile} not found. Falling back to english.");
$requested_idiom = 'english';
}
@@ -394,7 +394,7 @@ public function get_jquery_datepicker_regional($jquery_i18n_path)
if ( ! isset($this->jquery_datepicker_regional))
{
$datepicker_locales = [];
- foreach (glob("${jquery_i18n_path}/datepicker-*.js") as $filename)
+ foreach (glob("{$jquery_i18n_path}/datepicker-*.js") as $filename)
{
$res = preg_match('/datepicker-(.*)\.js/', $filename, $matches);
array_push($datepicker_locales, $matches[1]);
diff --git a/application/language/norwegian/date_lang.php b/application/language/norwegian/date_lang.php
new file mode 100644
index 000000000..81104118b
--- /dev/null
+++ b/application/language/norwegian/date_lang.php
@@ -0,0 +1,66 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/language/norwegian/kalkun_lang.php b/application/language/norwegian/kalkun_lang.php
new file mode 100644
index 000000000..e18e13632
--- /dev/null
+++ b/application/language/norwegian/kalkun_lang.php
@@ -0,0 +1,434 @@
+
+
+// Global
+$lang['Dashboard'] = 'Oversikt';
+$lang['Folders'] = 'Mapper';
+$lang['My folders'] = 'Mine mapper';
+
+$lang['Compose'] = 'Ny melding';
+$lang['Inbox'] = 'Innboks';
+$lang['Outbox'] = 'Utboks';
+$lang['Sent items'] = 'Sendte meldinger';
+$lang['Sending error'] = 'Feil ved sending';
+$lang['Trash'] = 'Søppel';
+$lang['Spam'] = 'Spam';
+$lang['Add'] = 'Legg til';
+$lang['Action'] = 'Handling';
+
+$lang['Phonebook'] = 'Kontakter';
+$lang['Settings'] = 'Instillinger';
+$lang['Filters'] = 'Filter';
+$lang['About {0}'] = 'Om {0}';
+$lang['Logout'] = 'Logg ut';
+
+// Dashboard
+$lang['Statistics'] = 'Statistikker';
+$lang['System information'] = 'System informasjon';
+$lang['Alerts'] = 'Advarsler';
+$lang['Operating system'] = 'Operativ system';
+$lang['Gammu version'] = 'Gammu versjon';
+$lang['Gammu DB schema'] = 'Gammu DB schema';
+$lang['Modem IMEI'] = 'Modem IMEI';
+
+// Phonebook
+$lang['Contact'] = 'Kontakt';
+$lang['All contacts'] = 'Alle kontakter';
+$lang['Send to all contacts'] = 'Send til alle kontakter';
+$lang['Add to group'] = 'Legg til i gruppe';
+$lang['Delete from group'] = 'Slett fra gruppe';
+$lang['Select add contact method'] = 'Velg metode for å legge til kontakt';
+$lang['Manual input'] = 'Legg til manuelt';
+$lang['Manually add contact using contact form'] = 'Legg til kontakt via skjema';
+$lang['From CSV file'] = 'Fra CSV fil';
+$lang['Import contact from CSV format file'] = 'Importer kontakt fra en CSV fil';
+$lang['CSV file'] = 'CSV fil';
+$lang['The CSV file must be in valid format'] = 'CVS-fila må være i et gyldig format';
+$lang['Are you sure you want to delete {0} contact(s)?'] = 'Er du sikker på at du vil slette {0} kontakt(er)?';
+$lang['valid example'] = 'Eksempel på gyldig format';
+
+// Message
+$lang['Message'] = 'Melding';
+$lang['Send to'] = 'Send til';
+$lang['Reply'] = 'Svar';
+$lang['Forward'] = 'Videresend';
+$lang['Forward to'] = 'Videresend til';
+$lang['Move to'] = 'Flytt til';
+$lang['Select folder'] = 'Velg mappe';
+$lang['Delete'] = 'Slett';
+$lang['Click to delete this folder'] = 'Klikk for å slette denne mappen';
+$lang['Recover'] = 'Gjenopprett';
+
+$lang['Send date'] = 'Send dato';
+$lang['Now'] = 'Nå';
+$lang['At date and time'] = 'På dato og tidspunkt';
+$lang['After a delay'] = 'Med forsinkelse';
+
+$lang['Input manually'] = 'Skriv nummer';
+
+$lang['Add folder'] = 'Legg til mappe';
+$lang['Folder name'] = 'Mappenavn';
+$lang['Cancel'] = 'Avbryt';
+$lang['Save'] = 'Lagre';
+$lang['Rename'] = 'Gi nytt navn';
+$lang['Rename folder'] = 'Gi nytt navn til mappe';
+$lang['Click to rename this folder'] = 'Klikk for å gi mappen nytt navn';
+
+$lang['This folder and all messages in it will be deleted permanently and cannot be recovered. Are you sure?'] = 'Denne mappen og alt innhold vil bli slettet permanent og kan ikke gjenopprettes. Er du sikker?';
+
+$lang['There is no message in {0}.'] = 'Det er ingen meldinger i {0}.';
+$lang['There is no message in this folder.'] = 'Det er ingen meldinger i denne mappen.';
+
+$lang['Delete all'] = 'Slett alle';
+$lang['Are you sure? This will affect all conversations.'] = 'Er du sikker? Dette vil gjelde alle samtaler.';
+
+$lang['Select all'] = 'Velg alle';
+$lang['Deselect all'] = 'Velg bort alle';
+$lang['Refresh'] = 'Oppdater';
+
+$lang['Report spam'] = 'Rapporter spam';
+$lang['Not spam'] = 'Ikke spam';
+
+
+$lang['SMSC'] = 'SMSC';
+$lang['Part'] = 'Del';
+$lang['Validity'] = 'Gyldighet';
+$lang['default'] = 'standard';
+$lang['5 minutes'] = '5 minutter';
+$lang['10 minutes'] = '10 minutter';
+$lang['30 minutes'] = '30 minutter';
+$lang['1 hour'] = '1 time';
+$lang['2 hours'] = '2 timer';
+$lang['4 hours'] = '4 timer';
+$lang['12 hours'] = '12 timer';
+$lang['1 day'] = '1 dag';
+$lang['2 days'] = '2 dager';
+$lang['5 days'] = '5 dager';
+$lang['1 week'] = '1 uke';
+$lang['2 weeks'] = '2 uker';
+$lang['4 weeks'] = '4 uker';
+$lang['maximum'] = 'maks';
+
+$lang['SMS type'] = 'SMS type';
+$lang['Normal'] = 'Normal';
+$lang['Flash'] = 'Flash';
+$lang['WAP push link'] = 'WAP push link';
+$lang['URL'] = 'URL';
+
+$lang['Ads is active'] = 'Reklame er aktivert';
+$lang['Check DND'] = 'Sjekk DND';
+$lang['Insert'] = 'Sett inn';
+
+$lang['Canned responses'] = 'Faste svar';
+$lang['There are no canned responses. Continue to save your present message as canned response.'] = 'Det finnes ingen faste svar. Fortsett for å lagre din nåværende melding som et fast svar.';
+$lang['Choose response'] = 'Velg svar';
+$lang['Saving...'] = 'Lagrer...';
+$lang['Are you sure?'] = 'Er du sikker?';
+
+// Others
+$lang['Amount'] = 'Beløp';
+$lang['times']['repetition'] = 'ganger';
+$lang['Hour(s)'] = 'Time(er)';
+$lang['Minutes'] = 'Minutter';
+$lang['No result.'] = 'Ingen resultat.';
+$lang['See conversation'] = 'Se samtale';
+
+$lang['Search'] = 'Søk';
+$lang['Advanced search'] = 'Avansert søk';
+$lang['Folder'] = 'Mappe';
+$lang['All'] = 'Alle';
+$lang['Date from'] = 'Dato fra';
+$lang['Date to'] = 'Dato til';
+$lang['Status'] = 'Status';
+$lang['Paging'] = 'Søker';
+$lang['{0} per page'] = '{0} per side';
+
+$lang['Resend'] = 'Send på nytt';
+$lang['Public contacts'] = 'Offentlige kontakter';
+$lang['Set as public contact'] = 'Gjør kontakten offentlig';
+$lang['My contacts'] = 'Mine kontakter';
+$lang['Public groups'] = 'Offentlige grupper';
+$lang['Set as public group'] = 'Gjør gruppen offentlig';
+$lang['My groups'] = 'Mine grupper';
+$lang['Incoming SMS'] = 'Innkommende SMS';
+$lang['Outgoing SMS'] = 'Utgående SMS';
+$lang['Delete all messages now'] = 'Slett alle beskjeder nå';
+$lang['Delete contact(s) confirmation'] = 'Slett kontakt(er) bekreftelse';
+$lang['Should be a valid URL'] = 'Må være en gyldig URL';
+$lang['Import from file'] = 'Importer fra fil';
+
+// Messages controller
+$lang['Outgoing SMS disabled.'] = 'Utgående SMS deaktivert.';
+$lang['A number was found in DND Resitry. SMS sending was skipped for it.'] = 'Et nummer ble funnet i DND registeret. SMS ble ikke sendt til dette nummeret.';
+$lang['Message delivered successfully to user inbox.'] = 'Meldingen ble levert til brukers innboks.';
+$lang['Copy of the message was placed in the outbox and is ready for delivery.'] = 'Kopi av meldingen ble lagt i utboks og er klar til levering.';
+$lang['No number found. SMS not sent.'] = 'Ingen nummer ble funnet. SMS ble ikke sendt';
+$lang['Only administrators can permanently delete messages.'] = 'Bare administratorer kan slette melding permanent.';
+
+// Setting
+$lang['Current password'] = 'Nåværende passord';
+$lang['Forgot your password?'] = 'Glemt passord?';
+$lang['New password'] = 'Nytt passord';
+$lang['Must be at least 6 characters long'] = 'Må være minst 6 karakterer langt';
+
+$lang['Enter your new password'] = 'Skriv inn nytt passord';
+
+$lang['Administrator'] = 'Administrator';
+$lang['User']['credentials'] = 'Bruker';
+
+$lang['Create a new filter'] = 'Lag nytt filter';
+$lang['Has the words'] = 'Har ordene';
+
+// SMS Content/Member
+$lang['Member'] = 'Medlem';
+$lang['Total member'] = 'Totalt antall medlemmer';
+$lang['There is no registered member yet'] = 'Det er ikke registrert noen medlemmer enda';
+
+// tni contribution
+$lang['Add contact'] = 'Legg til kontakt';
+$lang['Send message'] = 'Send melding';
+$lang['Send and repeat'] = 'Send og repeter';
+$lang['Sending'] = 'Sender';
+$lang['Insert name from contact list'] = 'Skriv inn navn fra kontaktlisten';
+$lang['Delete group(s) confirmation'] = 'Slett gruppe(r) bekreftelse';
+$lang['Delete group(s)?
+All their contacts will also be deleted.'] = 'Slett gruppe(r)?
+Alle kontaktene i gruppen vil også bli slettet.';
+$lang['Create group'] = 'Lag gruppe';
+$lang['Group name'] = 'Gruppenavn';
+$lang['Groups'] = 'Grupper';
+$lang['Manage groups'] = 'Behandle grupper';
+$lang['Manage group'] = 'Behandle gruppe';
+$lang['Manage contact'] = 'Behandle kontakt';
+$lang['Type group name'] = 'Skriv gruppenavn';
+$lang['No item selected.'] = 'Ingenting valgt.';
+$lang['No contact selected.'] = 'Ingen kontakter valgt.';
+$lang['Compose SMS'] = 'Lag ny SMS';
+$lang['Contacts'] = 'Kontakter';
+$lang['Back to {0}'] = 'Tilbake til {0}';
+$lang['Show details'] = 'Vis detaljer';
+$lang['Hide details'] = 'Skjul detaljer';
+$lang['Search contacts'] = 'Søk i kontakter';
+$lang['Search messages'] = 'Søk i meldinger';
+$lang['Edit'] = 'Rediger';
+$lang['All form fields are required.'] = 'Alle feltene må fylles ut.';
+$lang['Name'] = 'Navn';
+$lang['Telephone number'] = 'Telefonnummer';
+$lang['Email ID'] = 'Epost ID';
+$lang['Enable email forwarding'] = 'Aktiver videresending til epost';
+$lang['{0} remaining'] = '{0} gjenstående';
+$lang['{0} ago'] = '{0} siden';
+$lang['Edit contact'] = 'Rediger kontakt';
+$lang['Contact not found'] = 'Kontakt ikke funnet';
+$lang['No contacts in the database.'] = 'Ingen kontakter i databasen.';
+$lang['Add user'] = 'Legg til bruker';
+$lang['Edit user'] = 'Rediger bruker';
+$lang['User']['default'] = 'Bruker';
+$lang['Users'] = 'Brukere';
+$lang['This deletes the selected users and all their messages and contacts.'] = 'Dette sletter de valgte brukerne og alle deres beskjeder og kontakter.';
+$lang['User not found'] = 'Bruker ikke funnet';
+$lang['No users in the database.'] = 'Ingen brukere i databasen.';
+$lang['Username'] = 'Brukernavn';
+$lang['Password'] = 'Passord';
+$lang['Search user'] = 'Søk i brukere';
+$lang['Confirm password'] = 'Bekreft passord';
+$lang['Phone number'] = 'Telefonnummer';
+$lang['Action not allowed'] = 'Handling ikke tillatt';
+$lang['Field required.'] = 'Felt påkrevd.';
+$lang['Passwords do not match.'] = 'Passordene er ikke like.';
+$lang['No user selected'] = 'Ingen bruker valgt';
+$lang['Delete this folder'] = 'Slett denne mappen';
+$lang['Loading'] = 'Laster';
+$lang['Connected'] = 'Tilkoblet';
+$lang['Disconnected'] = 'Frakoblet';
+$lang['No group detected, add one first.'] = 'Ingen grupper funnet, legg til en først.';
+$lang['No group selected.'] = 'Ingen gruppe valgt.';
+$lang['From'] = 'Fra';
+$lang['To'] = 'Til';
+$lang['Inserted'] = 'Satt inn';
+$lang['Date'] = 'Dato';
+$lang['Sending failed'] = 'Sending feilet';
+$lang['Sent, no report'] = 'Sendt, ingen bekreftelse';
+$lang['Sent, waiting for report'] = 'Sendt, venter på bekreftelse';
+$lang['Delivered'] = 'Levert';
+$lang['Pending'] = 'Avventer';
+$lang['Unknown'] = 'Ukjent';
+$lang['Not set yet'] = 'Ikke valgt enda';
+
+$lang['Country calling code'] = 'Landskode';
+
+$lang['Conversation sort'] = 'Type samtale';
+
+$lang['Data per page'] = 'Data per side';
+$lang['Used for paging in message and phonebook'] = 'Brukt til personsøking i melding og kontakter';
+
+$lang['Permanent delete'] = 'Slett permanent';
+$lang['Disable'] = 'Deaktiver';
+$lang['Always move to trash first'] = 'Alltid flytt til papirkurv først';
+$lang['Enable'] = 'Aktiver';
+
+$lang['User settings'] = 'Brukerinnstillinger';
+$lang['General'] = 'Generelt';
+$lang['Personal'] = 'Personlig';
+
+$lang['Signature'] = 'Signatur';
+$lang['Max. 50 characters'] = 'Maks 50 tegn';
+$lang['Signature is added at the end of the message.'] = 'Signaturen blir lagt til på slutten av meldingen.';
+$lang['Language'] = 'Språk';
+$lang['Yes'] = 'Ja';
+$lang['No'] = 'Nei';
+$lang['Default'] = 'Standard';
+$lang['Delivery Report'] = 'Leveringsrapport';
+
+$lang['Delete copy (prevents duplicates).'] = 'Slett kopi (hindrer duplikater).';
+$lang['You are about to resend {0} message(s).'] = 'Du sender {0} melding(er).';
+
+// Kalkun Controller
+$lang['Outgoing SMS disabled. Contact system administrator.'] = 'Utgående SMS er deaktivert. Kontakt systemadministrator.';
+$lang['Wrong password'] = 'Feil passord';
+$lang['Username already taken'] = 'Brukernavn opptatt';
+$lang['Settings saved successfully.'] = 'Innstillnger lagret.';
+// Users Controller
+$lang['Access denied.'] = 'Ingen adgang.';
+$lang['User updated successfully.'] = 'Bruker oppdatert.';
+$lang['User added successfully.'] = 'Bruker lagt til.';
+// Pluginss Controller
+$lang['Access denied. Only administrators are allowed to manage plugins.'] = 'Ingen adgang. Bare administratorer kan behandle plugins.';
+$lang['Plugin {0} installed successfully.'] = 'Plugin {0} installert.';
+$lang['Plugin {0} uninstalled successfully.'] = 'Plugin {0} avinstallert.';
+$lang['Installed']['Plural'] = 'Installert';
+$lang['Available']['Plural'] = 'Tilgjengelig';
+// Phonebook Controller
+$lang['{0,number,integer} contacts imported successfully.'] = '{0,number,integer} kontakter importert.';
+$lang['Contact updated successfully.'] = 'Kontakt oppdatert.';
+$lang['Contact added successfully.'] = 'Kontakt lagt til.';
+// Gammu Model
+$lang['Message queued.'] = 'Melding sendt til kø.';
+$lang['Parameter invalid.'] = 'Ugyldig parameter.';
+
+$lang['403 Forbidden'] = '403 Forbudt';
+
+$lang['Close'] = 'Lukk';
+$lang['Previous'] = 'Forrige';
+$lang['Next'] = 'Neste';
+$lang['Continue'] = 'Fortsett';
+$lang['Submit']['form'] = 'Send';
+$lang['Log in'] = 'Logg inn';
+$lang['Username or password are incorrect.'] = 'Brukernavn eller passord er feil.';
+$lang['Token already generated and still active.'] = 'Token allerede generert og fremdeles aktiv.';
+$lang['To reset your Kalkun password please visit {0}'] = 'For å resette ditt Kalkun passord, vennligst besøk {0}';
+$lang['If you are a registered user, a SMS has been sent to you.'] = 'Hvis du er en registrert bruker, har det blitt sendt en SMS til deg.';
+$lang['Password changed successfully.'] = 'Passord er endret.';
+$lang['Token invalid.'] = 'Token ugyldig.';
+$lang['Password reset'] = 'Sett nytt passord';
+$lang['or'] = 'eller';
+$lang['Please enter your username and password'] = 'Vennligst skriv inn ditt brukernavn og passord';
+$lang['Remember me'] = 'Husk meg';
+$lang['Installation'] = 'Installasjon';
+$lang['Installation steps'] = 'Installasjonstrinn';
+$lang['Welcome screen'] = 'Velkomstside';
+$lang['Requirements check'] = 'Sjekk av forutsetninger';
+$lang['Database setup'] = 'Installasjon av database';
+$lang['Final configuration steps'] = 'Siste installasjonstrinn';
+$lang['Ok'] = 'Ok';
+$lang['Missing'] = 'Mangler';
+$lang['Found'] = 'Funnet';
+$lang['Successful'] = 'Suksess';
+$lang['Failed'] = 'Feilet';
+$lang['Kalkun installation assistant'] = 'Kalkun installasjonsassistent';
+$lang['This welcome screen'] = 'Denne velkomstsiden';
+$lang['Database installation or upgrade'] = 'Installasjon av database eller oppgradering';
+$lang['Keyboard shortcuts'] = 'Tastatur snarveier';
+$lang['Jumping'] = 'Hopp over';
+$lang['{0} then {1}:'] = '{0} så {1}:';
+$lang['Navigation'] = 'Navigasjon';
+$lang['Back to conversation list'] = 'Tilbake til samtaleliste';
+$lang['Highlight prev/next'] = 'Uthev forrige/neste';
+$lang['Open prev/next (message only)'] = 'Åpne forrige/neste (kun melding)';
+$lang['{0} or {1}:'] = '{0} eller {1}:';
+$lang['Open'] = 'Åpne';
+$lang['Selection'] = 'Valg';
+$lang['Select'] = 'Velg';
+$lang['Actions'] = 'Handlinger';
+$lang['Move selected'] = 'Flytt valgte';
+$lang['Delete selected'] = 'Slett valgte';
+$lang['Message details'] = 'Meldingsdetaljer';
+$lang['Application'] = 'Applikasjon';
+$lang['Open shortcut help'] = 'Åpne snarvei til hjelp';
+$lang['Error'] = 'Feil';
+$lang['Please specify a valid mobile phone number'] = 'Vennligst spesifiser et gyldig telefonnummer';
+$lang['Go to {0}'] = 'Gå til {0}';
+$lang['Please enter a name for your message. It should be unique.'] = 'Vennligst skriv inn et navn på meldingen. Dette bør være unikt.';
+$lang['Are you sure? This will overwrite the previous message.'] = 'Er du sikker? Dette vil overskrive forrige melding.';
+$lang['PHP Frontend for gammu-smsd'] = 'PHP Frontend for gammu-smsd';
+$lang['Authors'] = 'Forfattere';
+$lang['See {0} page'] = 'Se {0} side';
+$lang['Version'] = 'Versjon';
+$lang['Released'] = 'Sluppet';
+$lang['License'] = 'Lisens';
+$lang['Homepage'] = 'Hjemmeside';
+$lang['Add a new folder'] = 'Legg til ny mappe';
+$lang['Plugins'] = 'Plugins';
+$lang['No data'] = 'Ingen data';
+$lang['Select field'] = 'Velg felt';
+$lang['Delete folder'] = 'Slett mappe';
+$lang['Role'] = 'Rolle';
+$lang['Delete users'] = 'Slett brukere';
+$lang['Theme'] = 'Tema';
+$lang['Background image'] = 'Bakgrunnsbilde';
+$lang['Ascending'] = 'Stigende';
+$lang['Descending'] = 'Synkende';
+$lang['Value is too short.'] = 'For kort verdi.';
+$lang['Select group name'] = 'Velg gruppenavn';
+$lang['Uninstall'] = 'Avinstaller';
+$lang['Install'] = 'Installer';
+$lang['Author'] = 'Forfatter';
+$lang['No plugin available.'] = 'Ingen plugin tilgjengelig.';
+$lang['No plugin installed.'] = 'Ingen plugin installert.';
+$lang['Retrying now'] = 'Prøver på nytt nå';
+$lang['{0} character(s) / {1} message(s)'] = '{0} tegn / {1} beskjed(er)';
+$lang['{0} message(s) deleted'] = '{0} beskjed(er) slettet';
+$lang['{0} conversation(s) recovered'] = '{0} samtale(r) gjenopprettet';
+$lang['Messages moved successfully'] = 'Beskjeder flyttet';
+$lang['Outgoing message cannot be spam'] = 'Utgående meldinger kan ikke være spam.';
+$lang['Spam reported'] = 'Spam rapportert';
+$lang['Message(s) marked non-spam'] = 'Beskjed(er) merket som ikke spam';
+$lang['{0} conversation(s) deleted'] = '{0} samtale(r) slettet';
+$lang['{0} conversation(s) moved'] = '{0} samtale(r) flyttet';
+$lang['Value is too long.'] = 'For mange tegn.';
+$lang['Updated'] = 'Oppdater';
+$lang['Import'] = 'Importer';
+$lang['Reset search'] = 'Resett søk';
+$lang['No.']['Number abbreviation'] = 'Nr.';
+$lang['Insertion date'] = 'Innsettelsesdato';
+$lang['Control'] = 'Kontroll';
+$lang['Plugin {0} is not installed.'] = 'Plugin {0} er ikke installert.';
+$lang['Value must be a number.'] = 'Verdien må være et tall.';
+$lang['{0} part messages'] = '{0} delbeskjeder';
+$lang['Content'] = 'Innhold';
+$lang['No results for {0}'] = 'Ingen resultater for {0}';
+$lang['Failure to inject message into Gammu with gammu-smsd-inject. See kalkun logs.'] = 'Feilet i å legge inn melding til Gammu med gammu-smsd-inject. Se Kalkun logg.';
+$lang['Unknown error while sending WAP-LINK.'] = 'Ukjent feil ved sending av WAP-LINK.';
+$lang['Group'] = 'Gruppe';
+$lang['Delete the original message (prevents duplicates).'] = 'Slett den opprinnelige meldingen (unngå duplikater).';
+$lang['Delete permanently'] = 'Slett permanent';
+$lang['Retrying in {0} seconds.'] = 'Prøver på nytt om {0} sekunder.';
+$lang['Signal'] = 'Signalstyrke';
+$lang['Battery'] = 'Batteri';
+$lang['Writable'] = 'Skrivbar';
+$lang['Read-only'] = 'Kun lesetilgang';
+$lang['Inbox Master'] = 'Innboks Master';
+$lang['Network error.'] = 'Netverksfeil.';
+$lang['{0}%'] = '{0}%';
+$lang['Item deleted.'] = 'Innhold slettet.';
+$lang['Installation has been disabled by the administrator.
+To enable access to it, create a file named {0} in this directory of the server: {1}.
+Otherwise you may log-in at {2}.'] = 'Installasjon har blitt deaktivert av administrator.
+får å få tilgang til den, lag en fil med navn {0} i denne mappen på serveren: {1}.
+Ellers kan du logge inn på {2}.';
+$lang['There is no message in this conversation.'] = 'Det er ingen meldinger i denne samtalen.';
+$lang['Check again'] = 'Prøv igjen';
+$lang['Password modification forbidden in demo mode.'] = 'Endring av passord er ikke tillatt i demo-mode.';
+$lang['Settings saved successfully (except username for kalkun user which can\'t be changed in demo mode)'] = 'Innstillnger lagret (bortsett fra brukernavn for kalkun bruker, som ikke kan endres i demo-mode.)';
+$lang['Modification of username of "kalkun" user forbidden in demo mode. Username was restored.'] = 'Endring av brukernavn "kalkun" er ikke tillatt i demo-mode. Brukernavn ble gjenopprettet.';
diff --git a/application/language/norwegian/pagination_lang.php b/application/language/norwegian/pagination_lang.php
new file mode 100644
index 000000000..f62eb9bed
--- /dev/null
+++ b/application/language/norwegian/pagination_lang.php
@@ -0,0 +1,15 @@
+trigger_install_plugin($name);
+
}
}
}
@@ -328,9 +329,6 @@ public function activate_plugin($name)
{
$this->_ci->db->insert('plugins', array('plugin_system_name' => $name));
}
-
- // Run the activate hook
- self::do_action('activate_' . $name);
}
}
@@ -351,9 +349,6 @@ public function deactivate_plugin($name)
$this->_ci->db->where('plugin_system_name', $name)->delete('plugins');
if (isset(self::$plugins_pool[$name]))
self::$messages[] = "Plugin ".self::$plugins_pool[$name]['plugin_info']['plugin_name']." has been deactivated!";
-
- // Deactivate hook
- self::do_action('deactivate_' . $name);
}
}
@@ -444,7 +439,7 @@ public function do_action($name, $arguments = "")
{
return $arguments;
}
-
+
// Set the current running hook to this
self::$current_action = $name;
@@ -551,8 +546,49 @@ public function action_exists($name)
return false;
}
}
-
-
+
+ /**
+ * Triggers the functionname_activate function when a plugin is activated
+ *
+ * @param mixed $name
+ */
+ public function trigger_activate_plugin($name)
+ {
+ // Call plugin activate function
+ if (function_exists($name."_install"))
+ {
+ @call_user_func($name."_activate");
+ }
+ }
+
+ /**
+ * Triggers the functionname_deactivate function when a plugin is deactivated
+ *
+ * @param mixed $name
+ */
+ public function trigger_deactivate_plugin($name)
+ {
+ // Call our plugin deactivate function
+ if (function_exists($name."_install"))
+ {
+ @call_user_func($name."_deactivate");
+ }
+ }
+
+ /**
+ * Triggers the functionname_install function when a plugin is first installed
+ *
+ * @param mixed $name
+ */
+ public function trigger_install_plugin($name)
+ {
+ // Call our plugin deactivate function
+ if (function_exists($name."_install"))
+ {
+ @call_user_func($name."_install");
+ }
+ }
+
/**
* Will print our information about all plugins and actions
* neatly presented to the user.
diff --git a/application/models/Message_model.php b/application/models/Message_model.php
index 080da6281..683d88637 100644
--- a/application/models/Message_model.php
+++ b/application/models/Message_model.php
@@ -22,6 +22,8 @@
*/
class Message_model extends MY_Model {
+ private $gateway = '';
+
/**
* Constructor
*
diff --git a/application/models/Phonebook_model.php b/application/models/Phonebook_model.php
index f56bfbf50..d1f0e91ff 100644
--- a/application/models/Phonebook_model.php
+++ b/application/models/Phonebook_model.php
@@ -135,7 +135,7 @@ function get_phonebook($param)
$this->db->select('ID as id_pbk');
$this->db->from('pbk');
// phpcs:ignore CodeIgniter.Strings.DoubleQuoteUsage
- $this->db->where("({$this->_protect_identifiers('id_user')} = '${user_id}' OR {$this->_protect_identifiers('is_public')} = 'true')");
+ $this->db->where("({$this->_protect_identifiers('id_user')} = '{$user_id}' OR {$this->_protect_identifiers('is_public')} = 'true')");
$this->db->where_in('Number', $arr_number);
break;
@@ -167,7 +167,7 @@ function get_phonebook($param)
$condition1 = "({$this->_protect_identifiers('id_user')} = {$user_id} OR {$this->_protect_identifiers('is_public')} = 'true')";
$condition2_part1 = 'LOWER('.$this->db->protect_identifiers('Name').") LIKE '%".$search_word."%'";
$condition2_part2 = 'LOWER('.$this->db->protect_identifiers('Number').") LIKE '%".$search_word."%'";
- $condition2 = "(${condition2_part1} OR ${condition2_part2})";
+ $condition2 = "({$condition2_part1} OR {$condition2_part2})";
$this->db->where($condition1, NULL, FALSE);
$this->db->where($condition2, NULL, FALSE);
$this->db->order_by('Name');
diff --git a/application/models/gateway/Gammu_model.php b/application/models/gateway/Gammu_model.php
index 8956cfd17..5cbc4ad5f 100644
--- a/application/models/gateway/Gammu_model.php
+++ b/application/models/gateway/Gammu_model.php
@@ -77,7 +77,7 @@ function _send_wap_link($data)
}
else
{
- $this->db->update('outbox', array('SendingDateTime' => $data['date']), "ID = ${insert_id}");
+ $this->db->update('outbox', array('SendingDateTime' => $data['date']), "ID = {$insert_id}");
$this->Kalkun_model->add_sms_used($this->session->userdata('id_user'));
$f_ret = array('status' => tr_raw('Message queued.'));
}
@@ -892,7 +892,7 @@ function get_conversation($options = array())
$this->db->distinct();
//$this->db->from("($sub_sql) as ".$this->_protect_identifiers('maxresult').",inbox");
- $this->db->from("(${sub_sql}) as ".$this->_protect_identifiers('maxresult').',inbox');
+ $this->db->from("({$sub_sql}) as ".$this->_protect_identifiers('maxresult').',inbox');
$this->db->join('user_inbox', 'user_inbox.id_inbox=inbox.ID');
$this->db->where('id_user', $user_id);
$this->db->where('id_folder', $tmp_id_folder);
@@ -915,7 +915,7 @@ function get_conversation($options = array())
// $this->db->_reset_select();
$this->db->distinct();
- $this->db->from("(${sub_sql}) as ".$this->_protect_identifiers('maxresult').',outbox');
+ $this->db->from("({$sub_sql}) as ".$this->_protect_identifiers('maxresult').',outbox');
$this->db->join('user_outbox', 'outbox.ID=user_outbox.id_outbox');
$this->db->where('id_user', $user_id);
$this->db->where($this->_protect_identifiers('SendingDateTime'), $this->_protect_identifiers('maxresult.maxdate'), FALSE);
@@ -936,7 +936,7 @@ function get_conversation($options = array())
// $this->db->_reset_select();
$this->db->distinct();
- $this->db->from("(${sub_sql}) as ".$this->_protect_identifiers('maxresult').',sentitems');
+ $this->db->from("({$sub_sql}) as ".$this->_protect_identifiers('maxresult').',sentitems');
$this->db->join('user_sentitems', 'sentitems.ID=user_sentitems.id_sentitems');
$this->db->where('id_user', $user_id);
$this->db->where('id_folder', $tmp_id_folder);
diff --git a/application/models/gateway/Nongammu_model.php b/application/models/gateway/Nongammu_model.php
index ec3136180..71b2bd6e3 100644
--- a/application/models/gateway/Nongammu_model.php
+++ b/application/models/gateway/Nongammu_model.php
@@ -87,12 +87,12 @@ function send_messages($data)
}
$gateway = substr(get_class($this), 0, -6);
- log_message('debug', "SMS via gateway \"${gateway}\" to ".$data['dest'].' length '.strlen($data['message']).' chars');
+ log_message('debug', "SMS via gateway \"{$gateway}\" to ".$data['dest'].' length '.strlen($data['message']).' chars');
$ret = $this->really_send_messages($data);
if (is_string($ret))
{
- log_message('error', "Message failed via gateway \"${gateway}\" to ".$data['dest'].' Reason: '.$ret);
+ log_message('error', "Message failed via gateway \"{$gateway}\" to ".$data['dest'].' Reason: '.$ret);
$this->save_sent_messages($data, $ret);
return;
};
@@ -253,12 +253,12 @@ function process_outbox_queue()
$data['uid'] = $res2->row('id_user');
};
- log_message('debug', "SMS via gateway \"${gateway}\" to ".$data['dest'].
+ log_message('debug', "SMS via gateway \"{$gateway}\" to ".$data['dest'].
' length '.strlen($data['message']).' chars');
$ret = $this->really_send_messages($data);
if (is_string($ret))
{
- log_message('error', "Message failed via gateway \"${gateway}\" to ".$data['dest'].' Reason: '.$ret);
+ log_message('error', "Message failed via gateway \"{$gateway}\" to ".$data['dest'].' Reason: '.$ret);
$this->save_sent_messages($data, $ret);
return;
};
diff --git a/application/models/gateway/Tmobilecz_model.php b/application/models/gateway/Tmobilecz_model.php
index 0ef8e0f8b..2ea2f4e4b 100644
--- a/application/models/gateway/Tmobilecz_model.php
+++ b/application/models/gateway/Tmobilecz_model.php
@@ -143,7 +143,7 @@ function sendTMobileCZ($uid, $pwd, $phone, $msg, $isFlash = FALSE, $dRpt = FALSE
$cookies = $cache_path.'cookie_'.__CLASS__.'_'.$uid;
if ( ! is_really_writable($cache_path))
{
- return "Cookie file ${cookies} not writable";
+ return "Cookie file {$cookies} not writable";
}
if ((($cookiemt = filemtime($cookies)) !== FALSE) && ((time() - $cookiemt) > 300))
{ //cookies older than 5mins
diff --git a/application/plugins/Plugin_controller.php b/application/plugins/Plugin_controller.php
index 55cc8b04c..95817b2bf 100644
--- a/application/plugins/Plugin_controller.php
+++ b/application/plugins/Plugin_controller.php
@@ -31,6 +31,8 @@ function __construct($login = TRUE)
{
parent::__construct($login);
+ $this->load->helper('i18n');
+
// Prevent non-admin user
if ($login && $this->session->userdata('level') !== 'admin')
{
@@ -53,8 +55,19 @@ function __construct($login = TRUE)
$check = $CI->db->where('plugin_system_name', $this->plugin_name)->get('plugins');
if ($check->num_rows() !== 1)
{
- $this->session->set_flashdata('notif', tr_raw('Plugin {0} is not installed.', NULL, $this->plugin_name));
- redirect('pluginss');
+ $message = tr_raw('Plugin {0} is not installed.', NULL, $this->plugin_name);
+ $this->session->set_flashdata('notif', $message);
+ if ($this->plugin_name === 'rest_api')
+ {
+ // Special case for rest_api. If one makes a call to the rest_api while the plugin
+ // is not installed, the user wouldn't be notified because with rest_api plugin
+ // we don't use Kalkun's built-in authentification mechanism.
+ show_error($message, 503);
+ }
+ else
+ {
+ redirect('pluginss');
+ }
}
// Temporarily add the plugin path to package path to load language, config...
diff --git a/application/plugins/blacklist_number/media/pgsql_blacklist_number.sql b/application/plugins/blacklist_number/media/pgsql_blacklist_number.sql
index e08255e97..7743f2112 100644
--- a/application/plugins/blacklist_number/media/pgsql_blacklist_number.sql
+++ b/application/plugins/blacklist_number/media/pgsql_blacklist_number.sql
@@ -1,5 +1,5 @@
-CREATE TABLE "plugin_blacklist_number" (
+CREATE TABLE IF NOT EXISTS "plugin_blacklist_number" (
"id_blacklist_number" serial PRIMARY KEY,
"phone_number" varchar(15) NOT NULL,
"reason" varchar(255) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/blacklist_number/media/sqlite_blacklist_number.sql b/application/plugins/blacklist_number/media/sqlite_blacklist_number.sql
index 653877269..2c03a988c 100644
--- a/application/plugins/blacklist_number/media/sqlite_blacklist_number.sql
+++ b/application/plugins/blacklist_number/media/sqlite_blacklist_number.sql
@@ -1,5 +1,5 @@
-CREATE TABLE "plugin_blacklist_number" (
+CREATE TABLE IF NOT EXISTS "plugin_blacklist_number" (
"id_blacklist_number" INTEGER PRIMARY KEY AUTOINCREMENT,
"phone_number" VARCHAR(15) NOT NULL,
"reason" VARCHAR(255) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/jsonrpc/controllers/Jsonrpc.php b/application/plugins/jsonrpc/controllers/Jsonrpc.php
index 01a33d9f9..505a7ca9f 100644
--- a/application/plugins/jsonrpc/controllers/Jsonrpc.php
+++ b/application/plugins/jsonrpc/controllers/Jsonrpc.php
@@ -60,7 +60,7 @@ function send_sms_client()
}
catch (ErrorException $exception)
{
- echo "Exception sending jsonrpc query: ${exception}.message\n";
+ echo "Exception sending jsonrpc query: {$exception}.message\n";
exit(1);
}
diff --git a/application/plugins/rest_api/CREDITS b/application/plugins/rest_api/CREDITS
index 98b69f562..e9e68daf3 100644
--- a/application/plugins/rest_api/CREDITS
+++ b/application/plugins/rest_api/CREDITS
@@ -1,2 +1,2 @@
-CodeIgniter Rest Server v2.2
\ No newline at end of file
+CodeIgniter Rest Server v3.1.4
diff --git a/application/plugins/rest_api/config/rest.php b/application/plugins/rest_api/config/rest.php
index f7d6326a1..b4cc79844 100644
--- a/application/plugins/rest_api/config/rest.php
+++ b/application/plugins/rest_api/config/rest.php
@@ -1,27 +1,97 @@
function($username, $password)
+| In other cases override the function _perform_library_auth in your controller
+|
+| For digest authentication the library function should return already a stored
+| md5(username:restrealm:password) for that username
+|
+| e.g: md5('admin:REST API:1234') = '1e957ebc35631ab22d5bd6526bd14ea2'
+|
+*/
+$config['auth_library_class'] = '';
+$config['auth_library_function'] = '';
+
+/*
+|--------------------------------------------------------------------------
+| Override auth types for specific class/method
+|--------------------------------------------------------------------------
+|
+| Set specific authentication types for methods within a class (controller)
+|
+| Set as many config entries as needed. Any methods not set will use the default 'rest_auth' config value.
+|
+| e.g:
+|
+| $config['auth_override_class_method']['deals']['view'] = 'none';
+| $config['auth_override_class_method']['deals']['insert'] = 'digest';
+| $config['auth_override_class_method']['accounts']['user'] = 'basic';
+| $config['auth_override_class_method']['dashboard']['*'] = 'none|digest|basic';
+|
+| Here 'deals', 'accounts' and 'dashboard' are controller names, 'view', 'insert' and 'user' are methods within. An asterisk may also be used to specify an authentication method for an entire classes methods. Ex: $config['auth_override_class_method']['dashboard']['*'] = 'basic'; (NOTE: leave off the '_get' or '_post' from the end of the method name)
+| Acceptable values are; 'none', 'digest' and 'basic'.
+|
+*/
+// $config['auth_override_class_method']['deals']['view'] = 'none';
+// $config['auth_override_class_method']['deals']['insert'] = 'digest';
+// $config['auth_override_class_method']['accounts']['user'] = 'basic';
+// $config['auth_override_class_method']['dashboard']['*'] = 'basic';
+
+// ---Uncomment list line for the wildard unit test
+// $config['auth_override_class_method']['wildcard_test_cases']['*'] = 'basic';
+
+/*
+|--------------------------------------------------------------------------
+| Override auth types for specific 'class/method/HTTP method'
+|--------------------------------------------------------------------------
+|
+| example:
+|
+| $config['auth_override_class_method_http']['deals']['view']['get'] = 'none';
+| $config['auth_override_class_method_http']['deals']['insert']['post'] = 'none';
+| $config['auth_override_class_method_http']['deals']['*']['options'] = 'none';
+*/
+
+// ---Uncomment list line for the wildard unit test
+// $config['auth_override_class_method_http']['wildcard_test_cases']['*']['options'] = 'basic';
+
+/*
+|--------------------------------------------------------------------------
+| REST Login Usernames
+|--------------------------------------------------------------------------
+|
+| Array of usernames and passwords for login, if ldap is configured this is ignored
+|
+*/
+$config['rest_valid_logins'] = ['admin' => '1234'];
+
+/*
+|--------------------------------------------------------------------------
+| Global IP White-listing
+|--------------------------------------------------------------------------
+|
+| Limit connections to your REST server to White-listed IP addresses
+|
+| Usage:
+| 1. Set to TRUE and select an auth option for extreme security (client's IP
+| address must be in white-list and they must also log in)
+| 2. Set to TRUE with auth set to FALSE to allow White-listed IPs access with no login
+| 3. Set to FALSE but set 'auth_override_class_method' to 'white-list' to
+| restrict certain methods to IPs in your white-list
+|
+*/
+$config['rest_ip_whitelist_enabled'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| REST Handle Exceptions
+|--------------------------------------------------------------------------
+|
+| Handle exceptions caused by the controller
+|
+*/
+$config['rest_handle_exceptions'] = true;
+
+/*
+|--------------------------------------------------------------------------
+| REST IP White-list
+|--------------------------------------------------------------------------
+|
+| Limit connections to your REST server with a comma separated
+| list of IP addresses
+|
+| e.g: '123.456.789.0, 987.654.32.1'
+|
+| 127.0.0.1 and 0.0.0.0 are allowed by default
+|
+*/
+$config['rest_ip_whitelist'] = '';
+
+/*
+|--------------------------------------------------------------------------
+| Global IP Blacklisting
+|--------------------------------------------------------------------------
+|
+| Prevent connections to the REST server from blacklisted IP addresses
|
-| '' = no login required, 'basic' = unsecure login, 'digest' = more secure login
+| Usage:
+| 1. Set to TRUE and add any IP address to 'rest_ip_blacklist'
|
*/
-$config['rest_auth'] = '';
+$config['rest_ip_blacklist_enabled'] = false;
/*
|--------------------------------------------------------------------------
-| REST Login usernames
+| REST IP Blacklist
|--------------------------------------------------------------------------
|
-| Array of usernames and passwords for login
+| Prevent connections from the following IP addresses
|
-| array('admin' => '1234')
+| e.g: '123.456.789.0, 987.654.32.1'
|
*/
-$config['rest_valid_logins'] = array('admin' => '1234');
+$config['rest_ip_blacklist'] = '';
/*
|--------------------------------------------------------------------------
@@ -56,9 +285,7 @@
|--------------------------------------------------------------------------
|
| Connect to a database group for keys, logging, etc. It will only connect
-| if you have any of these features enabled.
-|
-| 'default'
+| if you have any of these features enabled
|
*/
$config['rest_database_group'] = 'default';
@@ -68,9 +295,7 @@
| REST API Keys Table Name
|--------------------------------------------------------------------------
|
-| The table name in your database that stores API Keys.
-|
-| 'keys'
+| The table name in your database that stores API keys
|
*/
$config['rest_keys_table'] = 'keys';
@@ -80,120 +305,261 @@
| REST Enable Keys
|--------------------------------------------------------------------------
|
-| When set to true REST_Controller will look for a key and match it to the DB.
-| If no key is provided, the request will return an error.
+| When set to TRUE, the REST API will look for a column name called 'key'.
+| If no key is provided, the request will result in an error. To override the
+| column name see 'rest_key_column'
+|
+| Default table schema:
+| CREATE TABLE `keys` (
+| `id` INT(11) NOT NULL AUTO_INCREMENT,
+| `user_id` INT(11) NOT NULL,
+| `key` VARCHAR(40) NOT NULL,
+| `level` INT(2) NOT NULL,
+| `ignore_limits` TINYINT(1) NOT NULL DEFAULT '0',
+| `is_private_key` TINYINT(1) NOT NULL DEFAULT '0',
+| `ip_addresses` TEXT NULL DEFAULT NULL,
+| `date_created` INT(11) NOT NULL,
+| PRIMARY KEY (`id`)
+| ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+|
+| For PostgreSQL
+| CREATE TABLE keys (
+| id SERIAL,
+| user_id INT NOT NULL,
+| key VARCHAR(40) NOT NULL,
+| level INT NOT NULL,
+| ignore_limits SMALLINT NOT NULL DEFAULT '0',
+| is_private_key SMALLINT NOT NULL DEFAULT '0',
+| ip_addresses TEXT NULL DEFAULT NULL,
+| date_created INT NOT NULL,
+| PRIMARY KEY (id)
+| ) ;
+| |
+*/
+$config['rest_enable_keys'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| REST Table Key Column Name
+|--------------------------------------------------------------------------
+|
+| If not using the default table schema in 'rest_enable_keys', specify the
+| column name to match e.g. my_key
|
-| FALSE
+*/
+$config['rest_key_column'] = 'key';
- CREATE TABLE `keys` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `key` varchar(40) NOT NULL,
- `level` int(2) NOT NULL,
- `ignore_limits` tinyint(1) NOT NULL DEFAULT '0',
- `date_created` int(11) NOT NULL,
- PRIMARY KEY (`id`)
- ) DEFAULT CHARSET=utf8;
+/*
+|--------------------------------------------------------------------------
+| REST API Limits method
+|--------------------------------------------------------------------------
+|
+| Specify the method used to limit the API calls
+|
+| Available methods are :
+| $config['rest_limits_method'] = 'IP_ADDRESS'; // Put a limit per ip address
+| $config['rest_limits_method'] = 'API_KEY'; // Put a limit per api key
+| $config['rest_limits_method'] = 'METHOD_NAME'; // Put a limit on method calls
+| $config['rest_limits_method'] = 'ROUTED_URL'; // Put a limit on the routed URL
|
*/
-$config['rest_enable_keys'] = FALSE;
+$config['rest_limits_method'] = 'ROUTED_URL';
/*
|--------------------------------------------------------------------------
| REST Key Length
|--------------------------------------------------------------------------
|
-| How long should created keys be? Double check this in your db schema.
+| Length of the created keys. Check your default database schema on the
+| maximum length allowed
|
-| Default: 32
-| Max: 40
+| Note: The maximum length is 40
|
*/
-$config['rest_key_length'] = 32;
+$config['rest_key_length'] = 40;
/*
|--------------------------------------------------------------------------
| REST API Key Variable
|--------------------------------------------------------------------------
|
-| Which variable will provide us the API Key
-|
-| Default: X-API-KEY
+| Custom header to specify the API key
+
+| Note: Custom headers with the X- prefix are deprecated as of
+| 2012/06/12. See RFC 6648 specification for more details
|
*/
$config['rest_key_name'] = 'X-API-KEY';
/*
|--------------------------------------------------------------------------
-| REST API Logs Table Name
+| REST Enable Logging
|--------------------------------------------------------------------------
|
-| The table name in your database that stores logs.
+| When set to TRUE, the REST API will log actions based on the column names 'key', 'date',
+| 'time' and 'ip_address'. This is a general rule that can be overridden in the
+| $this->method array for each controller
+|
+| Default table schema:
+| CREATE TABLE `logs` (
+| `id` INT(11) NOT NULL AUTO_INCREMENT,
+| `uri` VARCHAR(255) NOT NULL,
+| `method` VARCHAR(6) NOT NULL,
+| `params` TEXT DEFAULT NULL,
+| `api_key` VARCHAR(40) NOT NULL,
+| `ip_address` VARCHAR(45) NOT NULL,
+| `time` INT(11) NOT NULL,
+| `rtime` FLOAT DEFAULT NULL,
+| `authorized` VARCHAR(1) NOT NULL,
+| `response_code` smallint(3) DEFAULT '0',
+| PRIMARY KEY (`id`)
+| ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+|
+| For PostgreSQL
+| CREATE TABLE logs (
+| id SERIAL,
+| uri VARCHAR(255) NOT NULL,
+| method VARCHAR(6) NOT NULL,
+| params TEXT DEFAULT NULL,
+| api_key VARCHAR(40) NOT NULL,
+| ip_address VARCHAR(45) NOT NULL,
+| time INT NOT NULL,
+| rtime DOUBLE PRECISION DEFAULT NULL,
+| authorized boolean NOT NULL,
+| response_code smallint DEFAULT '0',
+| PRIMARY KEY (id)
+| ) ;
+*/
+$config['rest_enable_logging'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| REST API Logs Table Name
+|--------------------------------------------------------------------------
|
-| 'logs'
+| If not using the default table schema in 'rest_enable_logging', specify the
+| table name to match e.g. my_logs
|
*/
$config['rest_logs_table'] = 'logs';
/*
|--------------------------------------------------------------------------
-| REST Enable Logging
+| REST Method Access Control
|--------------------------------------------------------------------------
+| When set to TRUE, the REST API will check the access table to see if
+| the API key can access that controller. 'rest_enable_keys' must be enabled
+| to use this
+|
+| Default table schema:
+| CREATE TABLE `access` (
+| `id` INT(11) unsigned NOT NULL AUTO_INCREMENT,
+| `key` VARCHAR(40) NOT NULL DEFAULT '',
+| `all_access` TINYINT(1) NOT NULL DEFAULT '0',
+| `controller` VARCHAR(50) NOT NULL DEFAULT '',
+| `date_created` DATETIME DEFAULT NULL,
+| `date_modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+| PRIMARY KEY (`id`)
+| ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+|
+| For PostgreSQL
+| CREATE TABLE access (
+| id SERIAL,
+| key VARCHAR(40) NOT NULL DEFAULT '',
+| all_access SMALLINT NOT NULL DEFAULT '0',
+| controller VARCHAR(50) NOT NULL DEFAULT '',
+| date_created TIMESTAMP(0) DEFAULT NULL,
+| date_modified TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
+| PRIMARY KEY (id)
+| ) ;
+| CREATE OR REPLACE FUNCTION upd_timestamp() RETURNS TRIGGER
+| LANGUAGE plpgsql
+| AS
+| $$
+| BEGIN
+| NEW.modified = CURRENT_TIMESTAMP;
+| RETURN NEW;
+| END;
+| $$;
+| CREATE TRIGGER trigger_access
+| BEFORE UPDATE
+| ON access
+| FOR EACH ROW
+| EXECUTE PROCEDURE upd_timestamp();
|
-| When set to true REST_Controller will log actions based on key, date,
-| time and IP address. This is a general rule that can be overridden in the
-| $this->method array in each controller.
-|
-| FALSE
+*/
+$config['rest_enable_access'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| REST API Access Table Name
+|--------------------------------------------------------------------------
|
- CREATE TABLE `logs` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `uri` varchar(255) NOT NULL,
- `method` varchar(6) NOT NULL,
- `params` text NOT NULL,
- `api_key` varchar(40) NOT NULL,
- `ip_address` varchar(15) NOT NULL,
- `time` int(11) NOT NULL,
- `authorized` tinyint(1) NOT NULL,
- PRIMARY KEY (`id`)
- ) DEFAULT CHARSET=utf8;
+| If not using the default table schema in 'rest_enable_access', specify the
+| table name to match e.g. my_access
|
*/
-$config['rest_enable_logging'] = FALSE;
+$config['rest_access_table'] = 'access';
/*
|--------------------------------------------------------------------------
-| REST API Limits Table Name
+| REST API Param Log Format
|--------------------------------------------------------------------------
|
-| The table name in your database that stores limits.
-|
-| 'logs'
+| When set to TRUE, the REST API log parameters will be stored in the database as JSON
+| Set to FALSE to log as serialized PHP
|
*/
-$config['rest_limits_table'] = 'limits';
+$config['rest_logs_json_params'] = false;
/*
|--------------------------------------------------------------------------
| REST Enable Limits
|--------------------------------------------------------------------------
|
-| When set to true REST_Controller will count the number of uses of each method
+| When set to TRUE, the REST API will count the number of uses of each method
| by an API key each hour. This is a general rule that can be overridden in the
-| $this->method array in each controller.
-|
-| FALSE
+| $this->method array in each controller
+|
+| Default table schema:
+| CREATE TABLE `limits` (
+| `id` INT(11) NOT NULL AUTO_INCREMENT,
+| `uri` VARCHAR(255) NOT NULL,
+| `count` INT(10) NOT NULL,
+| `hour_started` INT(11) NOT NULL,
+| `api_key` VARCHAR(40) NOT NULL,
+| PRIMARY KEY (`id`)
+| ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+|
+| For PostgreSQL
+| CREATE TABLE limits (
+| id SERIAL,
+| uri VARCHAR(255) NOT NULL,
+| count INT NOT NULL,
+| hour_started INT NOT NULL,
+| api_key VARCHAR(40) NOT NULL,
+| PRIMARY KEY (id)
+| ) ;
+|
+| To specify the limits within the controller's __construct() method, add per-method
+| limits with:
+|
+| $this->methods['METHOD_NAME']['limit'] = [NUM_REQUESTS_PER_HOUR];
+|
+| See application/controllers/api/example.php for examples
+*/
+$config['rest_enable_limits'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| REST API Limits Table Name
+|--------------------------------------------------------------------------
|
- CREATE TABLE `limits` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `uri` varchar(255) NOT NULL,
- `count` int(10) NOT NULL,
- `hour_started` int(11) NOT NULL,
- `api_key` varchar(40) NOT NULL,
- PRIMARY KEY (`id`)
- ) DEFAULT CHARSET=utf8;
+| If not using the default table schema in 'rest_enable_limits', specify the
+| table name to match e.g. my_limits
|
*/
-$config['rest_enable_limits'] = FALSE;
+$config['rest_limits_table'] = 'limits';
/*
|--------------------------------------------------------------------------
@@ -203,8 +569,120 @@
| Set to TRUE to ignore the HTTP Accept and speed up each request a little.
| Only do this if you are using the $this->rest_format or /format/xml in URLs
|
-| FALSE
+*/
+$config['rest_ignore_http_accept'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| REST AJAX Only
+|--------------------------------------------------------------------------
+|
+| Set to TRUE to allow AJAX requests only. Set to FALSE to accept HTTP requests
+|
+| Note: If set to TRUE and the request is not AJAX, a 505 response with the
+| error message 'Only AJAX requests are accepted.' will be returned.
+|
+| Hint: This is good for production environments
+|
+*/
+$config['rest_ajax_only'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| REST Language File
+|--------------------------------------------------------------------------
+|
+| Language file to load from the language directory
+|
+*/
+$config['rest_language'] = 'english';
+
+/*
+|--------------------------------------------------------------------------
+| CORS Check
+|--------------------------------------------------------------------------
+|
+| Set to TRUE to enable Cross-Origin Resource Sharing (CORS). Useful if you
+| are hosting your API on a different domain from the application that
+| will access it through a browser
+|
+*/
+$config['check_cors'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| CORS Allowable Headers
+|--------------------------------------------------------------------------
+|
+| If using CORS checks, set the allowable headers here
+|
+*/
+$config['allowed_cors_headers'] = [
+ 'Origin',
+ 'X-Requested-With',
+ 'Content-Type',
+ 'Accept',
+ 'Access-Control-Request-Method',
+];
+
+/*
+|--------------------------------------------------------------------------
+| CORS Allowable Methods
+|--------------------------------------------------------------------------
+|
+| If using CORS checks, you can set the methods you want to be allowed
+|
+*/
+$config['allowed_cors_methods'] = [
+ 'GET',
+ 'POST',
+ 'OPTIONS',
+ 'PUT',
+ 'PATCH',
+ 'DELETE',
+];
+
+/*
+|--------------------------------------------------------------------------
+| CORS Allow Any Domain
+|--------------------------------------------------------------------------
+|
+| Set to TRUE to enable Cross-Origin Resource Sharing (CORS) from any
+| source domain
+|
+*/
+$config['allow_any_cors_domain'] = false;
+
+/*
+|--------------------------------------------------------------------------
+| CORS Allowable Domains
+|--------------------------------------------------------------------------
+|
+| Used if $config['check_cors'] is set to TRUE and $config['allow_any_cors_domain']
+| is set to FALSE. Set all the allowable domains within the array
+|
+| e.g. $config['allowed_origins'] = ['http://www.example.com', 'https://spa.example.com']
+|
+*/
+$config['allowed_cors_origins'] = [];
+
+/*
+|--------------------------------------------------------------------------
+| CORS Forced Headers
+|--------------------------------------------------------------------------
+|
+| If using CORS checks, always include the headers and values specified here
+| in the OPTIONS client preflight.
+| Example:
+| $config['forced_cors_headers'] = [
+| 'Access-Control-Allow-Credentials' => 'true'
+| ];
+|
+| Added because of how Sencha Ext JS framework requires the header
+| Access-Control-Allow-Credentials to be set to true to allow the use of
+| credentials in the REST Proxy.
+| See documentation here:
+| http://docs.sencha.com/extjs/6.5.2/classic/Ext.data.proxy.Rest.html#cfg-withCredentials
|
*/
-// phpcs:enable
-$config['rest_ignore_http_accept'] = FALSE;
+$config['forced_cors_headers'] = [];
diff --git a/application/plugins/rest_api/controllers/Rest_api.php b/application/plugins/rest_api/controllers/Rest_api.php
index 483883824..6878f6cf2 100644
--- a/application/plugins/rest_api/controllers/Rest_api.php
+++ b/application/plugins/rest_api/controllers/Rest_api.php
@@ -18,13 +18,13 @@
* @subpackage Plugin
* @category Controllers
*/
-include_once(APPPATH.'plugins/rest_api/libraries/REST_Controller.php');
+include_once(APPPATH.'plugins/rest_api/libraries/RestController.php');
-class Rest_api extends REST_Controller {
+class Rest_api extends RestController {
function __construct()
{
- parent::__construct(FALSE);
+ parent::__construct();
}
/**
diff --git a/application/plugins/rest_api/language/bulgarian/index.html b/application/plugins/rest_api/language/bulgarian/index.html
new file mode 100644
index 000000000..b702fbc39
--- /dev/null
+++ b/application/plugins/rest_api/language/bulgarian/index.html
@@ -0,0 +1,11 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/bulgarian/rest_controller_lang.php b/application/plugins/rest_api/language/bulgarian/rest_controller_lang.php
new file mode 100644
index 000000000..4ba134d87
--- /dev/null
+++ b/application/plugins/rest_api/language/bulgarian/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/dutch/rest_controller_lang.php b/application/plugins/rest_api/language/dutch/rest_controller_lang.php
new file mode 100644
index 000000000..45fd9c257
--- /dev/null
+++ b/application/plugins/rest_api/language/dutch/rest_controller_lang.php
@@ -0,0 +1,16 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/english/rest_controller_lang.php b/application/plugins/rest_api/language/english/rest_controller_lang.php
new file mode 100644
index 000000000..06bf4b966
--- /dev/null
+++ b/application/plugins/rest_api/language/english/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/french/rest_controller_lang.php b/application/plugins/rest_api/language/french/rest_controller_lang.php
new file mode 100644
index 000000000..20641de8a
--- /dev/null
+++ b/application/plugins/rest_api/language/french/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/german/rest_controller_lang.php b/application/plugins/rest_api/language/german/rest_controller_lang.php
new file mode 100644
index 000000000..3099d932f
--- /dev/null
+++ b/application/plugins/rest_api/language/german/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/greek/rest_controller_lang.php b/application/plugins/rest_api/language/greek/rest_controller_lang.php
new file mode 100644
index 000000000..eb68c39ec
--- /dev/null
+++ b/application/plugins/rest_api/language/greek/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/indonesia/index.html b/application/plugins/rest_api/language/indonesia/index.html
new file mode 100644
index 000000000..b702fbc39
--- /dev/null
+++ b/application/plugins/rest_api/language/indonesia/index.html
@@ -0,0 +1,11 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/indonesia/rest_controller_lang.php b/application/plugins/rest_api/language/indonesia/rest_controller_lang.php
new file mode 100644
index 000000000..9931e18b5
--- /dev/null
+++ b/application/plugins/rest_api/language/indonesia/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/italian/rest_controller_lang.php b/application/plugins/rest_api/language/italian/rest_controller_lang.php
new file mode 100644
index 000000000..783f16ab9
--- /dev/null
+++ b/application/plugins/rest_api/language/italian/rest_controller_lang.php
@@ -0,0 +1,16 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/korean/rest_controller_lang.php b/application/plugins/rest_api/language/korean/rest_controller_lang.php
new file mode 100644
index 000000000..fd2fb4836
--- /dev/null
+++ b/application/plugins/rest_api/language/korean/rest_controller_lang.php
@@ -0,0 +1,16 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/portuguese-brazilian/rest_controller_lang.php b/application/plugins/rest_api/language/portuguese-brazilian/rest_controller_lang.php
new file mode 100644
index 000000000..10c164c68
--- /dev/null
+++ b/application/plugins/rest_api/language/portuguese-brazilian/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/romanian/rest_controller_lang.php b/application/plugins/rest_api/language/romanian/rest_controller_lang.php
new file mode 100644
index 000000000..3231a7c56
--- /dev/null
+++ b/application/plugins/rest_api/language/romanian/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/serbian_cyr/rest_controller_lang.php b/application/plugins/rest_api/language/serbian_cyr/rest_controller_lang.php
new file mode 100644
index 000000000..c828cc0a8
--- /dev/null
+++ b/application/plugins/rest_api/language/serbian_cyr/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/serbian_lat/rest_controller_lang.php b/application/plugins/rest_api/language/serbian_lat/rest_controller_lang.php
new file mode 100644
index 000000000..6046788d4
--- /dev/null
+++ b/application/plugins/rest_api/language/serbian_lat/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/simplified-chinese/rest_controller_lang.php b/application/plugins/rest_api/language/simplified-chinese/rest_controller_lang.php
new file mode 100644
index 000000000..9e7629739
--- /dev/null
+++ b/application/plugins/rest_api/language/simplified-chinese/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/spanish/rest_controller_lang.php b/application/plugins/rest_api/language/spanish/rest_controller_lang.php
new file mode 100644
index 000000000..f98078fb2
--- /dev/null
+++ b/application/plugins/rest_api/language/spanish/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/traditional-chinese/rest_controller_lang.php b/application/plugins/rest_api/language/traditional-chinese/rest_controller_lang.php
new file mode 100644
index 000000000..a8450f2bc
--- /dev/null
+++ b/application/plugins/rest_api/language/traditional-chinese/rest_controller_lang.php
@@ -0,0 +1,18 @@
+
+
+
+ 403 Forbidden
+
+
+
+Directory access is forbidden.
+
+
+
diff --git a/application/plugins/rest_api/language/turkish/rest_controller_lang.php b/application/plugins/rest_api/language/turkish/rest_controller_lang.php
new file mode 100644
index 000000000..589b28ccf
--- /dev/null
+++ b/application/plugins/rest_api/language/turkish/rest_controller_lang.php
@@ -0,0 +1,18 @@
+_CI = &get_instance();
+
+ // Load the inflector helper
+ $this->_CI->load->helper('inflector');
+
+ // If the provided data is already formatted we should probably convert it to an array
+ if ($from_type !== null) {
+ if (method_exists($this, '_from_'.$from_type)) {
+ $data = call_user_func([$this, '_from_'.$from_type], $data);
+ } else {
+ throw new Exception('Format class does not support conversion from "'.$from_type.'".');
+ }
+ }
+
+ // Set the member variable to the data passed
+ $this->_data = $data;
+ }
+
+ /**
+ * Create an instance of the format class
+ * e.g: echo $this->format->factory(['foo' => 'bar'])->to_csv();.
+ *
+ * @param mixed $data Data to convert/parse
+ * @param string $from_type Type to convert from e.g. json, csv, html
+ *
+ * @return object Instance of the format class
+ */
+ public static function factory($data, $from_type = null)
+ {
+ // $class = __CLASS__;
+ // return new $class();
+
+ return new static($data, $from_type);
+ }
+
+ // FORMATTING OUTPUT ---------------------------------------------------------
+
+ /**
+ * Format data as an array.
+ *
+ * @param mixed|null $data Optional data to pass, so as to override the data passed
+ * to the constructor
+ *
+ * @return array Data parsed as an array; otherwise, an empty array
+ */
+ public function to_array($data = null)
+ {
+ // If no data is passed as a parameter, then use the data passed
+ // via the constructor
+ if ($data === null && func_num_args() === 0) {
+ $data = $this->_data;
+ }
+
+ // Cast as an array if not already
+ if (is_array($data) === false) {
+ $data = (array) $data;
+ }
+
+ $array = [];
+ foreach ((array) $data as $key => $value) {
+ if (is_object($value) === true || is_array($value) === true) {
+ $array[$key] = $this->to_array($value);
+ } else {
+ $array[$key] = $value;
+ }
+ }
+
+ return $array;
+ }
+
+ /**
+ * Format data as XML.
+ *
+ * @param mixed|null $data Optional data to pass, so as to override the data passed
+ * to the constructor
+ * @param null $structure
+ * @param string $basenode
+ *
+ * @return mixed
+ */
+ public function to_xml($data = null, $structure = null, $basenode = 'xml')
+ {
+ if ($data === null && func_num_args() === 0) {
+ $data = $this->_data;
+ }
+
+ if ($structure === null) {
+ $structure = simplexml_load_string("<$basenode />");
+ }
+
+ // Force it to be something useful
+ if (is_array($data) === false && is_object($data) === false) {
+ $data = (array) $data;
+ }
+
+ foreach ($data as $key => $value) {
+
+ //change false/true to 0/1
+ if (is_bool($value)) {
+ $value = (int) $value;
+ }
+
+ // no numeric keys in our xml please!
+ if (is_numeric($key)) {
+ // make string key...
+ $key = (singular($basenode) != $basenode) ? singular($basenode) : 'item';
+ }
+
+ // replace anything not alpha numeric
+ $key = preg_replace('/[^a-z_\-0-9]/i', '', $key);
+
+ if ($key === '_attributes' && (is_array($value) || is_object($value))) {
+ $attributes = $value;
+ if (is_object($attributes)) {
+ $attributes = get_object_vars($attributes);
+ }
+
+ foreach ($attributes as $attribute_name => $attribute_value) {
+ $structure->addAttribute($attribute_name, $attribute_value);
+ }
+ }
+ // if there is another array found recursively call this function
+ elseif (is_array($value) || is_object($value)) {
+ $node = $structure->addChild($key);
+
+ // recursive call.
+ $this->to_xml($value, $node, $key);
+ } else {
+ // add single node.
+ $value = htmlspecialchars(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), ENT_QUOTES, 'UTF-8');
+
+ $structure->addChild($key, $value);
+ }
+ }
+
+ return $structure->asXML();
+ }
+
+ /**
+ * Format data as HTML.
+ *
+ * @param mixed|null $data Optional data to pass, so as to override the data passed
+ * to the constructor
+ *
+ * @return mixed
+ */
+ public function to_html($data = null)
+ {
+ // If no data is passed as a parameter, then use the data passed
+ // via the constructor
+ if ($data === null && func_num_args() === 0) {
+ $data = $this->_data;
+ }
+
+ // Cast as an array if not already
+ if (is_array($data) === false) {
+ $data = (array) $data;
+ }
+
+ // Check if it's a multi-dimensional array
+ if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE)) {
+ // Multi-dimensional array
+ $headings = array_keys($data[0]);
+ } else {
+ // Single array
+ $headings = array_keys($data);
+ $data = [$data];
+ }
+
+ // Load the table library
+ $this->_CI->load->library('table');
+
+ $this->_CI->table->set_heading($headings);
+
+ foreach ($data as $row) {
+ // Suppressing the "array to string conversion" notice
+ // Keep the "evil" @ here
+ $row = @array_map('strval', $row);
+
+ $this->_CI->table->add_row($row);
+ }
+
+ return $this->_CI->table->generate();
+ }
+
+ /**
+ * @link http://www.metashock.de/2014/02/create-csv-file-in-memory-php/
+ *
+ * @param mixed|null $data Optional data to pass, so as to override the data passed
+ * to the constructor
+ * @param string $delimiter The optional delimiter parameter sets the field
+ * delimiter (one character only). NULL will use the default value (,)
+ * @param string $enclosure The optional enclosure parameter sets the field
+ * enclosure (one character only). NULL will use the default value (")
+ *
+ * @return string A csv string
+ */
+ public function to_csv($data = null, $delimiter = ',', $enclosure = '"')
+ {
+ // Use a threshold of 1 MB (1024 * 1024)
+ $handle = fopen('php://temp/maxmemory:1048576', 'w');
+ if ($handle === false) {
+ return;
+ }
+
+ // If no data is passed as a parameter, then use the data passed
+ // via the constructor
+ if ($data === null && func_num_args() === 0) {
+ $data = $this->_data;
+ }
+
+ // If NULL, then set as the default delimiter
+ if ($delimiter === null) {
+ $delimiter = ',';
+ }
+
+ // If NULL, then set as the default enclosure
+ if ($enclosure === null) {
+ $enclosure = '"';
+ }
+
+ // Cast as an array if not already
+ if (is_array($data) === false) {
+ $data = (array) $data;
+ }
+
+ // Check if it's a multi-dimensional array
+ if (isset($data[0]) && count($data) !== count($data, COUNT_RECURSIVE)) {
+ // Multi-dimensional array
+ $headings = array_keys($data[0]);
+ } else {
+ // Single array
+ $headings = array_keys($data);
+ $data = [$data];
+ }
+
+ // Apply the headings
+ fputcsv($handle, $headings, $delimiter, $enclosure);
+
+ foreach ($data as $record) {
+ // If the record is not an array, then break. This is because the 2nd param of
+ // fputcsv() should be an array
+ if (is_array($record) === false) {
+ break;
+ }
+
+ // Suppressing the "array to string conversion" notice.
+ // Keep the "evil" @ here.
+ $record = @array_map('strval', $record);
+
+ // Returns the length of the string written or FALSE
+ fputcsv($handle, $record, $delimiter, $enclosure);
+ }
+
+ // Reset the file pointer
+ rewind($handle);
+
+ // Retrieve the csv contents
+ $csv = stream_get_contents($handle);
+
+ // Close the handle
+ fclose($handle);
+
+ // Convert UTF-8 encoding to UTF-16LE which is supported by MS Excel
+ $csv = mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
+
+ return $csv;
+ }
+
+ /**
+ * Encode data as json.
+ *
+ * @param mixed|null $data Optional data to pass, so as to override the data passed
+ * to the constructor
+ *
+ * @return string Json representation of a value
+ */
+ public function to_json($data = null)
+ {
+ // If no data is passed as a parameter, then use the data passed
+ // via the constructor
+ if ($data === null && func_num_args() === 0) {
+ $data = $this->_data;
+ }
+
+ // Get the callback parameter (if set)
+ $callback = $this->_CI->input->get('callback');
+
+ if (empty($callback) === true) {
+ return json_encode($data, JSON_UNESCAPED_UNICODE);
+ }
+
+ // We only honour a jsonp callback which are valid javascript identifiers
+ elseif (preg_match('/^[a-z_\$][a-z0-9\$_]*(\.[a-z_\$][a-z0-9\$_]*)*$/i', $callback)) {
+ // Return the data as encoded json with a callback
+ return $callback.'('.json_encode($data, JSON_UNESCAPED_UNICODE).');';
+ }
+
+ // An invalid jsonp callback function provided.
+ // Though I don't believe this should be hardcoded here
+ $data['warning'] = 'INVALID JSONP CALLBACK: '.$callback;
+
+ return json_encode($data, JSON_UNESCAPED_UNICODE);
+ }
+
+ /**
+ * Encode data as a serialized array.
+ *
+ * @param mixed|null $data Optional data to pass, so as to override the data passed
+ * to the constructor
+ *
+ * @return string Serialized data
+ */
+ public function to_serialized($data = null)
+ {
+ // If no data is passed as a parameter, then use the data passed
+ // via the constructor
+ if ($data === null && func_num_args() === 0) {
+ $data = $this->_data;
+ }
+
+ return serialize($data);
+ }
+
+ /**
+ * Format data using a PHP structure.
+ *
+ * @param mixed|null $data Optional data to pass, so as to override the data passed
+ * to the constructor
+ *
+ * @return mixed String representation of a variable
+ */
+ public function to_php($data = null)
+ {
+ // If no data is passed as a parameter, then use the data passed
+ // via the constructor
+ if ($data === null && func_num_args() === 0) {
+ $data = $this->_data;
+ }
+
+ return var_export($data, true);
+ }
+
+ // INTERNAL FUNCTIONS
+
+ /**
+ * @param string $data XML string
+ *
+ * @return array XML element object; otherwise, empty array
+ */
+ protected function _from_xml($data)
+ {
+ return $data ? (array) simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA) : [];
+ }
+
+ /**
+ * @param string $data CSV string
+ * @param string $delimiter The optional delimiter parameter sets the field
+ * delimiter (one character only). NULL will use the default value (,)
+ * @param string $enclosure The optional enclosure parameter sets the field
+ * enclosure (one character only). NULL will use the default value (")
+ *
+ * @return array A multi-dimensional array with the outer array being the number of rows
+ * and the inner arrays the individual fields
+ */
+ protected function _from_csv($data, $delimiter = ',', $enclosure = '"')
+ {
+ // If NULL, then set as the default delimiter
+ if ($delimiter === null) {
+ $delimiter = ',';
+ }
+
+ // If NULL, then set as the default enclosure
+ if ($enclosure === null) {
+ $enclosure = '"';
+ }
+
+ return str_getcsv($data, $delimiter, $enclosure);
+ }
+
+ /**
+ * @param string $data Encoded json string
+ *
+ * @return mixed Decoded json string with leading and trailing whitespace removed
+ */
+ protected function _from_json($data)
+ {
+ return json_decode(trim($data));
+ }
+
+ /**
+ * @param string $data Data to unserialize
+ *
+ * @return mixed Unserialized data
+ */
+ protected function _from_serialize($data)
+ {
+ return unserialize(trim($data));
+ }
+
+ /**
+ * @param string $data Data to trim leading and trailing whitespace
+ *
+ * @return string Data with leading and trailing whitespace removed
+ */
+ protected function _from_php($data)
+ {
+ return trim($data);
+ }
+}
diff --git a/application/plugins/rest_api/libraries/REST_Controller.php b/application/plugins/rest_api/libraries/REST_Controller.php
deleted file mode 100644
index 71102b2f0..000000000
--- a/application/plugins/rest_api/libraries/REST_Controller.php
+++ /dev/null
@@ -1,841 +0,0 @@
- 'application/xml',
- 'rawxml' => 'application/xml',
- 'json' => 'application/json',
- 'jsonp' => 'application/json',
- 'serialize' => 'application/vnd.php.serialized',
- 'php' => 'text/plain',
- 'html' => 'text/html',
- 'csv' => 'application/csv'
- );
-
- // Constructor function
- function __construct()
- {
- parent::__construct(FALSE);
- $this->request = new \stdClass();
-
- // How is this request being made? POST, DELETE, GET, PUT?
- $this->request->method = $this->_detect_method();
-
- // Lets grab the config and get ready to party
- $this->load->config('rest');
-
- if ($this->config->item('rest_auth') == 'basic')
- {
- $this->_prepare_basic_auth();
- }
-
- elseif ($this->config->item('rest_auth') == 'digest')
- {
- $this->_prepare_digest_auth();
- }
-
- // Some Methods cant have a body
- $this->request->body = NULL;
-
- switch ($this->request->method)
- {
- case 'get':
- // Grab proper GET variables
- parse_str(parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY), $get);
-
- // If there are any, populate $this->_get_args
- empty($get) OR $this->_get_args = $get;
- break;
-
- case 'post':
- $this->_post_args = $_POST;
-
- // It might be a HTTP body
- $this->request->body = file_get_contents('php://input');
- break;
-
- case 'put':
- // It might be a HTTP body
- $this->request->body = file_get_contents('php://input');
-
- // Try and set up our PUT variables anyway in case its not
- parse_str($this->request->body, $this->_put_args);
- break;
-
- case 'delete':
- // Set up out PUT variables
- parse_str(file_get_contents('php://input'), $this->_delete_args);
- break;
- }
-
- // Set up our GET variables
- $this->_get_args = array_merge($this->_get_args, $this->uri->ruri_to_assoc());
-
- // Merge both for one mega-args variable
- $this->_args = array_merge($this->_get_args, $this->_put_args, $this->_post_args, $this->_delete_args);
-
- // Which format should the data be returned in?
- $this->request->format = $this->_detect_format();
-
- // Which format should the data be returned in?
- $this->request->lang = $this->_detect_lang();
-
- // Load DB if its enabled
- if (config_item('rest_database_group') AND (config_item('rest_enable_keys') OR config_item('rest_enable_logging')))
- {
- $this->rest->db = $this->load->database(config_item('rest_database_group'), TRUE);
- }
-
- // Checking for keys? GET TO WORK!
- if (config_item('rest_enable_keys'))
- {
- $this->_allow = $this->_detect_api_key();
- }
- }
-
- /*
- * Remap
- *
- * Requests are not made to methods directly The request will be for an "object".
- * this simply maps the object and method to the correct Controller method.
- */
- function _remap($object_called)
- {
- $controller_method = $object_called.'_'.$this->request->method;
-
- // Do we want to log this method (if allowed by config)?
- $log_method = ! (isset($this->methods[$controller_method]['log']) AND $this->methods[$controller_method]['log'] == FALSE);
-
- // Use keys for this method?
- $use_key = ! (isset($this->methods[$controller_method]['key']) AND $this->methods[$controller_method]['key'] == FALSE);
-
- // Get that useless shitty key out of here
- if (config_item('rest_enable_keys') AND $use_key AND $this->_allow === FALSE)
- {
- $this->response(array('status' => 0, 'error' => 'Invalid API Key.'), 403);
- return;
- }
-
- // Sure it exists, but can they do anything with it?
- if ( ! method_exists($this, $controller_method))
- {
- $this->response(array('status' => 0, 'error' => 'Unknown method.'), 404);
- return;
- }
-
- // Doing key related stuff? Can only do it if they have a key right?
- if (config_item('rest_enable_keys') AND ! empty($this->rest->key))
- {
- // Check the limit
- if ( config_item('rest_enable_limits') AND ! $this->_check_limit($controller_method))
- {
- $this->response(array('status' => 0, 'error' => 'This API key has reached the hourly limit for this method.'), 401);
- return;
- }
-
- // If no level is set use 0, they probably aren't using permissions
- $level = isset($this->methods[$controller_method]['level']) ? $this->methods[$controller_method]['level'] : 0;
-
- // If no level is set, or it is lower than/equal to the key's level
- $authorized = $level <= $this->rest->level;
-
- // IM TELLIN!
- if (config_item('rest_enable_logging') AND $log_method)
- {
- $this->_log_request($authorized);
- }
-
- // They don't have good enough perms
- if ( ! $authorized)
- {
- $this->response(array('status' => 0, 'error' => 'This API key does not have enough permissions.'), 401);
- return;
- }
- }
-
- // No key stuff, but record that stuff is happening
- else if (config_item('rest_enable_logging') AND $log_method)
- {
- $this->_log_request($authorized = TRUE);
- }
-
- // And...... GO!
- $this->$controller_method();
- }
-
- /*
- * response
- *
- * Takes pure data and optionally a status code, then creates the response
- */
- function response($data = array(), $http_code = 200)
- {
- if (empty($data))
- {
- $this->output->set_status_header(404);
- return;
- }
-
- $this->output->set_status_header($http_code);
-
- // If the format method exists, call and return the output in that format
- if (method_exists($this, '_format_'.$this->request->format))
- {
- // Set the correct format header
- $this->output->set_header('Content-type: '.$this->_supported_formats[$this->request->format]);
-
- $formatted_data = $this->{'_format_'.$this->request->format}($data);
- $this->output->set_output($formatted_data);
- }
-
- // Format not supported, output directly
- else
- {
- $this->output->set_output($data);
- }
- }
-
- /*
- * Detect format
- *
- * Detect which format should be used to output the data
- */
- private function _detect_format()
- {
- $pattern = '/\.(' . implode( '|', array_keys($this->_supported_formats) ) . ')$/';
-
- // Check if a file extension is used
- if (preg_match($pattern, end($this->_get_args), $matches))
- {
- // The key of the last argument
- $last_key = end( array_keys($this->_get_args));
-
- // Remove the extension from arguments too
- $this->_get_args[$last_key] = preg_replace($pattern, '', $this->_get_args[$last_key]);
- $this->_args[$last_key] = preg_replace($pattern, '', $this->_args[$last_key]);
-
- return $matches[1];
- }
-
- // A format has been passed as an argument in the URL and it is supported
- if (isset($this->_args['format']) AND isset($this->_supported_formats))
- {
- return $this->_args['format'];
- }
-
- // Otherwise, check the HTTP_ACCEPT (if it exists and we are allowed)
- if ($this->config->item('rest_ignore_http_accept') === FALSE AND $this->input->server('HTTP_ACCEPT'))
- {
- // Check all formats against the HTTP_ACCEPT header
- foreach(array_keys($this->_supported_formats) as $format)
- {
- // Has this format been requested?
- if (strpos($this->input->server('HTTP_ACCEPT'), $format) !== FALSE)
- {
- // If not HTML or XML assume its right and send it on its way
- if ($format != 'html' AND $format != 'xml')
- {
-
- return $format;
- }
-
- // HTML or XML have shown up as a match
- else
- {
- // If it is truely HTML, it wont want any XML
- if ($format == 'html' AND strpos($this->input->server('HTTP_ACCEPT'), 'xml') === FALSE)
- {
- return $format;
- }
-
- // If it is truely XML, it wont want any HTML
- elseif ($format == 'xml' AND strpos($this->input->server('HTTP_ACCEPT'), 'html') === FALSE)
- {
- return $format;
- }
- }
- }
- }
-
- } // End HTTP_ACCEPT checking
-
- // Well, none of that has worked! Let's see if the controller has a default
- if (!empty($this->rest_format))
- {
- return $this->rest_format;
- }
-
- // Just use the default format
- return config_item('rest_default_format');
- }
-
-
- /*
- * Detect method
- *
- * Detect which method (POST, PUT, GET, DELETE) is being used
- */
- private function _detect_method()
- {
- $method = strtolower($this->input->server('REQUEST_METHOD'));
- if (in_array($method, array('get', 'delete', 'post', 'put')))
- {
- return $method;
- }
-
- return 'get';
- }
-
-
- /*
- * Detect API Key
- *
- * See if the user has provided an API key
- */
- private function _detect_api_key()
- {
- // Work out the name of the SERVER entry based on config
- $key_name = 'HTTP_'.strtoupper(str_replace('-', '_', config_item('rest_key_name')));
-
- $this->rest->key = NULL;
- $this->rest->level = NULL;
- $this->rest->ignore_limits = FALSE;
-
- // Find the key from server or arguments
- if ($key = isset($this->_args['API-Key']) ? $this->_args['API-Key'] : $this->input->server($key_name))
- {
- if ( ! $row = $this->rest->db->where('key', $key)->get(config_item('rest_keys_table'))->row())
- {
- return FALSE;
- }
-
- $this->rest->key = $row->key;
- $this->rest->level = $row->level;
- $this->rest->ignore_limits = $row->ignore_limits;
-
- return TRUE;
- }
-
- // No key has been sent
- return FALSE;
- }
-
-
- /*
- * Detect language(s)
- *
- * What language do they want it in?
- */
- private function _detect_lang()
- {
- if ( ! $lang = $this->input->server('HTTP_ACCEPT_LANGUAGE'))
- {
- return NULL;
- }
-
- // They might have sent a few, make it an array
- if (strpos($lang, ',') !== FALSE)
- {
- $langs = explode(',', $lang);
-
- $return_langs = array();
- $i = 1;
- foreach ($langs as $lang)
- {
- // Remove weight and strip space
- list($lang) = explode(';', $lang);
- $return_langs[] = trim($lang);
- }
-
- return $return_langs;
- }
-
- // Nope, just return the string
- return $lang;
- }
-
-
- /*
- * Log request
- *
- * Record the entry for awesomeness purposes
- */
- private function _log_request($authorized = FALSE)
- {
- return $this->rest->db->insert(config_item('rest_logs_table'), array(
- 'uri' => $this->uri->uri_string(),
- 'method' => $this->request->method,
- 'params' => serialize($this->_args),
- 'api_key' => isset($this->rest->key) ? $this->rest->key : '',
- 'ip_address' => $this->input->ip_address(),
- 'time' => function_exists('now') ? now() : time(),
- 'authorized' => $authorized
- ));
- }
-
-
- /*
- * Log request
- *
- * Record the entry for awesomeness purposes
- */
- private function _check_limit($controller_method)
- {
- // They are special, or it might not even have a limit
- if ( ! empty($this->rest->ignore_limits) OR ! isset($this->methods[$controller_method]['limit']))
- {
- // On your way sonny-jim.
- return TRUE;
- }
-
- // How many times can you get to this method an hour?
- $limit = $this->methods[$controller_method]['limit'];
-
- // Get data on a keys usage
- $result = $this->rest->db
- ->where('uri', $this->uri->uri_string())
- ->where('api_key', $this->rest->key)
- ->get(config_item('rest_limits_table'))
- ->row();
-
- // No calls yet, or been an hour since they called
- if ( ! $result OR $result->hour_started < time()-(60*60))
- {
- // Right, set one up from scratch
- $this->rest->db->insert('limits', array(
- 'uri' => $this->uri->uri_string(),
- 'api_key' => isset($this->rest->key) ? $this->rest->key : '',
- 'count' => 1,
- 'hour_started' => time()
- ));
- }
-
- // They have called within the hour, so lets update
- else
- {
- // Your luck is out, you've called too many times!
- if ($result->count > $limit)
- {
- return FALSE;
- }
-
- $this->rest->db
- ->where('uri', $this->uri->uri_string())
- ->where('api_key', $this->rest->key)
- ->set('count', 'count + 1', FALSE)
- ->update(config_item('limits'));
- }
-
- return TRUE;
- }
-
- // INPUT FUNCTION --------------------------------------------------------------
-
- public function get($key = NULL, $xss_clean = TRUE)
- {
- if ($key === NULL)
- {
- return $this->_get_args;
- }
-
- return array_key_exists($key, $this->_get_args) ? $this->_xss_clean($this->_get_args[$key], $xss_clean) : FALSE;
- }
-
- public function post($key = NULL, $xss_clean = TRUE)
- {
- if ($key === NULL)
- {
- return $this->_post_args;
- }
-
- return $this->input->post($key, $xss_clean);
- }
-
- public function put($key = NULL, $xss_clean = TRUE)
- {
- if ($key === NULL)
- {
- return $this->_put_args;
- }
-
- return array_key_exists($key, $this->_put_args) ? $this->_xss_clean( $this->_put_args[$key], $xss_clean ) : FALSE;
- }
-
- public function delete($key = NULL, $xss_clean = TRUE)
- {
- if ($key === NULL)
- {
- return $this->_delete_args;
- }
-
- return array_key_exists($key, $this->_delete_args) ? $this->_xss_clean( $this->_delete_args[$key], $xss_clean ) : FALSE ;
- }
-
- private function _xss_clean($val, $bool)
- {
- if(CI_VERSION < 2)
- {
- return $bool ? $this->input->xss_clean($val) : $val;
- }
-
- else
- {
- return $bool ? $this->security->xss_clean($val) : $val;
- }
- }
-
- public function validation_errors()
- {
- $string = strip_tags($this->form_validation->error_string());
-
- return explode("\n", trim($string, "\n"));
- }
-
- // SECURITY FUNCTIONS ---------------------------------------------------------
-
- private function _check_login($username = '', $password = NULL)
- {
- if (empty($username))
- {
- return FALSE;
- }
-
- $valid_logins = $this->config->item('rest_valid_logins');
-
- if ( ! array_key_exists($username, $valid_logins))
- {
- return FALSE;
- }
-
- // If actually NULL (not empty string) then do not check it
- if ($password !== NULL AND $valid_logins[$username] != $password)
- {
- return FALSE;
- }
-
- return TRUE;
- }
-
- private function _prepare_basic_auth()
- {
- $username = NULL;
- $password = NULL;
-
- // mod_php
- if ($this->input->server('PHP_AUTH_USER'))
- {
- $username = $this->input->server('PHP_AUTH_USER');
- $password = $this->input->server('PHP_AUTH_PW');
- }
-
- // most other servers
- elseif ($this->input->server('HTTP_AUTHENTICATION'))
- {
- if (strpos(strtolower($this->input->server('HTTP_AUTHENTICATION')),'basic') === 0)
- {
- list($username,$password) = explode(':',base64_decode(substr($this->input->server('HTTP_AUTHORIZATION'), 6)));
- }
- }
-
- if ( ! $this->_check_login($username, $password) )
- {
- $this->_force_login();
- }
-
- }
-
- private function _prepare_digest_auth()
- {
- $uniqid = uniqid(""); // Empty argument for backward compatibility
-
- // We need to test which server authentication variable to use
- // because the PHP ISAPI module in IIS acts different from CGI
- if ($this->input->server('PHP_AUTH_DIGEST'))
- {
- $digest_string = $this->input->server('PHP_AUTH_DIGEST');
- }
-
- elseif ($this->input->server('HTTP_AUTHORIZATION'))
- {
- $digest_string = $this->input->server('HTTP_AUTHORIZATION');
- }
-
- else
- {
- $digest_string = "";
- }
-
- /* The $_SESSION['error_prompted'] variabile is used to ask
- the password again if none given or if the user enters
- a wrong auth. informations. */
- if ( empty($digest_string) )
- {
- $this->_force_login($uniqid);
- }
-
- // We need to retrieve authentication informations from the $auth_data variable
- preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response)=[\'"]?([^\'",]+)@', $digest_string, $matches);
- $digest = array_combine($matches[1], $matches[2]);
-
- if ( ! array_key_exists('username', $digest) OR !$this->_check_login($digest['username']) )
- {
- $this->_force_login($uniqid);
- }
-
- $valid_logins = $this->config->item('rest_valid_logins');
- $valid_pass = $valid_logins[$digest['username']];
-
- // This is the valid response expected
- $A1 = md5($digest['username'] . ':' . $this->config->item('rest_realm') . ':' . $valid_pass);
- $A2 = md5(strtoupper($this->request->method).':'.$digest['uri']);
- $valid_response = md5($A1.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$A2);
-
- if ($digest['response'] != $valid_response)
- {
- header('HTTP/1.0 401 Unauthorized');
- header('HTTP/1.1 401 Unauthorized');
- exit;
- }
-
- }
-
-
- private function _force_login($nonce = '')
- {
- header('HTTP/1.0 401 Unauthorized');
- header('HTTP/1.1 401 Unauthorized');
-
- if ($this->config->item('rest_auth') == 'basic')
- {
- header('WWW-Authenticate: Basic realm="'.$this->config->item('rest_realm').'"');
- }
-
- elseif ($this->config->item('rest_auth') == 'digest')
- {
- header('WWW-Authenticate: Digest realm="'.$this->config->item('rest_realm'). '" qop="auth" nonce="'.$nonce.'" opaque="'.md5($this->config->item('rest_realm')).'"');
- }
-
- exit('Not authorized.');
- }
-
- // Force it into an array
- private function _force_loopable($data)
- {
- // Force it to be something useful
- if ( ! is_array($data) AND ! is_object($data))
- {
- $data = (array) $data;
- }
-
- return $data;
- }
- // FORMATING FUNCTIONS ---------------------------------------------------------
-
- // Format XML for output
- private function _format_xml($data = array(), $structure = NULL, $basenode = 'xml')
- {
- // turn off compatibility mode as simple xml throws a wobbly if you don't.
- if (ini_get('zend.ze1_compatibility_mode') == 1)
- {
- ini_set('zend.ze1_compatibility_mode', 0);
- }
-
- if ($structure == NULL)
- {
- $structure = simplexml_load_string("<$basenode />");
- }
-
- // loop through the data passed in.
- $data = $this->_force_loopable($data);
- foreach($data as $key => $value)
- {
- // no numeric keys in our xml please!
- if (is_numeric($key))
- {
- // make string key...
- //$key = "item_". (string) $key;
- $key = "item";
- }
-
- // replace anything not alpha numeric
- $key = preg_replace('/[^a-z_]/i', '', $key);
-
- // if there is another array found recrusively call this function
- if (is_array($value) OR is_object($value))
- {
- $node = $structure->addChild($key);
- // recrusive call.
- $this-> _format_xml($value, $node, $basenode);
- }
-
- else
- {
- // Actual boolean values need to be converted to numbers
- is_bool($value) AND $value = (int) $value;
-
- // add single node.
- $value = htmlentities($value, ENT_NOQUOTES, "UTF-8");
-
- $UsedKeys[] = $key;
-
- $structure->addChild($key, $value);
- }
- }
-
- // pass back as string. or simple xml object if you want!
- return $structure->asXML();
- }
-
-
- // Format Raw XML for output
- private function _format_rawxml($data = array(), $structure = NULL, $basenode = 'xml')
- {
- // turn off compatibility mode as simple xml throws a wobbly if you don't.
- if (ini_get('zend.ze1_compatibility_mode') == 1)
- {
- ini_set('zend.ze1_compatibility_mode', 0);
- }
-
- if ($structure == NULL)
- {
- $structure = simplexml_load_string("<$basenode />");
- }
-
- // loop through the data passed in.
- $data = $this->_force_loopable($data);
- foreach( $data as $key => $value)
- {
- // no numeric keys in our xml please!
- if (is_numeric($key))
- {
- // make string key...
- //$key = "item_". (string) $key;
- $key = "item";
- }
-
- // replace anything not alpha numeric
- $key = preg_replace('/[^a-z0-9_-]/i', '', $key);
-
- // if there is another array found recrusively call this function
- if (is_array($value) OR is_object($value))
- {
- $node = $structure->addChild($key);
- // recrusive call.
- $this->_format_rawxml($value, $node, $basenode);
- }
-
- else
- {
- // Actual boolean values need to be converted to numbers
- is_bool($value) AND $value = (int) $value;
-
- // add single node.
- $value = htmlentities($value, ENT_NOQUOTES, "UTF-8");
-
- $UsedKeys[] = $key;
-
- $structure->addChild($key, $value);
- }
-
- }
-
- // pass back as string. or simple xml object if you want!
- return $structure->asXML();
- }
-
- // Format HTML for output
- private function _format_html($data = array())
- {
- // Multi-dimentional array
- if (isset($data[0]) && is_array($data[0]))
- {
- $headings = array_keys($data[0]);
- }
-
- // Single array
- else
- {
- $headings = array_keys($data);
- $data = array($data);
- }
-
- $this->load->library('table');
-
- $this->table->set_heading($headings);
-
- foreach($data as &$row)
- {
- $this->table->add_row($row);
- }
-
- return $this->table->generate();
- }
-
- // Format HTML for output
- private function _format_csv($data = array())
- {
- // Multi-dimentional array
- if (isset($data[0]))
- {
- $headings = array_keys($data[0]);
- }
-
- // Single array
- else
- {
- $headings = array_keys($data);
- $data = array($data);
- }
-
- $output = implode(',', $headings)."\r\n";
- foreach($data as &$row)
- {
- $output .= '"'.implode('","', $row)."\"\r\n";
- }
-
- return $output;
- }
-
- // Encode as JSON
- private function _format_json($data = array())
- {
- return json_encode($data);
- }
-
- // Encode as JSONP
- private function _format_jsonp($data = array())
- {
- return $this->get('callback').'('.json_encode($data).')';
- }
-
- // Encode as Serialized array
- private function _format_serialize($data = array())
- {
- return serialize($data);
- }
-
- // Encode raw PHP
- private function _format_php($data = array())
- {
- return var_export($data, TRUE);
- }
-}
diff --git a/application/plugins/rest_api/libraries/RestController.php b/application/plugins/rest_api/libraries/RestController.php
new file mode 100644
index 000000000..8c7d38697
--- /dev/null
+++ b/application/plugins/rest_api/libraries/RestController.php
@@ -0,0 +1,2046 @@
+ 'application/json',
+ 'array' => 'application/json',
+ 'csv' => 'application/csv',
+ 'html' => 'text/html',
+ 'jsonp' => 'application/javascript',
+ 'php' => 'text/plain',
+ 'serialized' => 'application/vnd.php.serialized',
+ 'xml' => 'application/xml',
+ ];
+
+ /**
+ * Information about the current API user.
+ *
+ * @var object
+ */
+ protected $_apiuser;
+
+ /**
+ * Whether or not to perform a CORS check and apply CORS headers to the request.
+ *
+ * @var bool
+ */
+ protected $check_cors = null;
+
+ /**
+ * Enable XSS flag
+ * Determines whether the XSS filter is always active when
+ * GET, OPTIONS, HEAD, POST, PUT, DELETE and PATCH data is encountered
+ * Set automatically based on config setting.
+ *
+ * @var bool
+ */
+ protected $_enable_xss = false;
+
+ private $is_valid_request = true;
+
+ /**
+ * Common HTTP status codes and their respective description.
+ *
+ * @link http://www.restapitutorial.com/httpstatuscodes.html
+ */
+ const HTTP_OK = 200;
+ const HTTP_CREATED = 201;
+ const HTTP_NOT_MODIFIED = 304;
+ const HTTP_BAD_REQUEST = 400;
+ const HTTP_UNAUTHORIZED = 401;
+ const HTTP_FORBIDDEN = 403;
+ const HTTP_NOT_FOUND = 404;
+ const HTTP_METHOD_NOT_ALLOWED = 405;
+ const HTTP_NOT_ACCEPTABLE = 406;
+ const HTTP_INTERNAL_ERROR = 500;
+
+ /**
+ * @var Format
+ */
+ private $format;
+
+ /**
+ * @var bool
+ */
+ protected $auth_override;
+
+ /**
+ * Extend this function to apply additional checking early on in the process.
+ *
+ * @return void
+ */
+ protected function early_checks()
+ {
+ }
+
+ /**
+ * Constructor for the REST API.
+ *
+ * @param string $config Configuration filename minus the file extension
+ * e.g: my_rest.php is passed as 'my_rest'
+ */
+ public function __construct($config = 'rest')
+ {
+ parent::__construct(NULL);
+
+ // Set the default value of global xss filtering. Same approach as CodeIgniter 3
+ $this->_enable_xss = ($this->config->item('global_xss_filtering') === true);
+
+ // Don't try to parse template variables like {elapsed_time} and {memory_usage}
+ // when output is displayed for not damaging data accidentally
+ $this->output->parse_exec_vars = false;
+
+ // Load the rest.php configuration file
+ $this->load->add_package_path(APPPATH.'plugins/rest_api', false);
+ $this->load->config($config, false);
+ $this->load->remove_package_path(APPPATH.'plugins/rest_api', false);
+
+ // Log the loading time to the log table
+ if ($this->config->item('rest_enable_logging') === true) {
+ // Start the timer for how long the request takes
+ $this->_start_rtime = microtime(true);
+ }
+
+ // Determine supported output formats from configuration
+ $supported_formats = $this->config->item('rest_supported_formats');
+
+ // Validate the configuration setting output formats
+ if (empty($supported_formats)) {
+ $supported_formats = [];
+ }
+
+ if (!is_array($supported_formats)) {
+ $supported_formats = [$supported_formats];
+ }
+
+ // Add silently the default output format if it is missing
+ $default_format = $this->_get_default_output_format();
+ if (!in_array($default_format, $supported_formats)) {
+ $supported_formats[] = $default_format;
+ }
+
+ // Now update $this->_supported_formats
+ $this->_supported_formats = array_intersect_key($this->_supported_formats, array_flip($supported_formats));
+
+ // Get the language
+ $language = $this->config->item('rest_language');
+ if ($language === null) {
+ $language = 'english';
+ }
+
+ // Load the language file
+ $this->lang->load('rest_controller', $language, false, true, __DIR__.'/../');
+
+ // Initialise the response, request and rest objects
+ $this->request = new stdClass();
+ $this->response = new stdClass();
+ $this->rest = new stdClass();
+
+ // Check to see if the current IP address is blacklisted
+ if ($this->config->item('rest_ip_blacklist_enabled') === true) {
+ $this->_check_blacklist_auth();
+ }
+
+ // Determine whether the connection is HTTPS
+ $this->request->ssl = is_https();
+
+ // How is this request being made? GET, POST, PATCH, DELETE, INSERT, PUT, HEAD or OPTIONS
+ $this->request->method = $this->_detect_method();
+
+ // Check for CORS access request
+ $check_cors = $this->config->item('check_cors');
+ if ($check_cors === true) {
+ $this->_check_cors();
+ }
+
+ // Create an argument container if it doesn't exist e.g. _get_args
+ if (isset($this->{'_'.$this->request->method.'_args'}) === false) {
+ $this->{'_'.$this->request->method.'_args'} = [];
+ }
+
+ // Set up the query parameters
+ $this->_parse_query();
+
+ // Set up the GET variables
+ $this->_get_args = array_merge($this->_get_args, $this->uri->ruri_to_assoc());
+
+ // Try to find a format for the request (means we have a request body)
+ $this->request->format = $this->_detect_input_format();
+
+ // Not all methods have a body attached with them
+ $this->request->body = null;
+
+ $this->{'_parse_'.$this->request->method}();
+
+ // Fix parse method return arguments null
+ if ($this->{'_'.$this->request->method.'_args'} === null) {
+ $this->{'_'.$this->request->method.'_args'} = [];
+ }
+
+ // Which format should the data be returned in?
+ $this->response->format = $this->_detect_output_format();
+
+ // Which language should the data be returned in?
+ $this->response->lang = $this->_detect_lang();
+
+ // Now we know all about our request, let's try and parse the body if it exists
+ if ($this->request->format && $this->request->body) {
+ $this->request->body = Format::factory($this->request->body, $this->request->format)->to_array();
+
+ // Assign payload arguments to proper method container
+ $this->{'_'.$this->request->method.'_args'} = $this->request->body;
+ }
+
+ //get header vars
+ $this->_head_args = $this->input->request_headers();
+
+ // Merge both for one mega-args variable
+ $this->_args = array_merge(
+ $this->_get_args,
+ $this->_options_args,
+ $this->_patch_args,
+ $this->_head_args,
+ $this->_put_args,
+ $this->_post_args,
+ $this->_delete_args,
+ $this->{'_'.$this->request->method.'_args'}
+ );
+
+ // Extend this function to apply additional checking early on in the process
+ $this->early_checks();
+
+ // Load DB if its enabled
+ if ($this->config->item('rest_database_group') && ($this->config->item('rest_enable_keys') || $this->config->item('rest_enable_logging'))) {
+ $this->rest->db = $this->load->database($this->config->item('rest_database_group'), true);
+ }
+
+ // Use whatever database is in use (isset returns FALSE)
+ elseif (property_exists($this, 'db')) {
+ $this->rest->db = $this->db;
+ }
+
+ // Check if there is a specific auth type for the current class/method
+ // _auth_override_check could exit so we need $this->rest->db initialized before
+ $this->auth_override = $this->_auth_override_check();
+
+ // Checking for keys? GET TO WorK!
+ // Skip keys test for $config['auth_override_class_method']['class'['method'] = 'none'
+ if ($this->config->item('rest_enable_keys') && $this->auth_override !== true) {
+ $this->_allow = $this->_detect_api_key();
+ }
+
+ // Only allow ajax requests
+ if ($this->input->is_ajax_request() === false && $this->config->item('rest_ajax_only')) {
+ // Display an error response
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ajax_only'),
+ ], self::HTTP_NOT_ACCEPTABLE);
+ }
+
+ // When there is no specific override for the current class/method, use the default auth value set in the config
+ if ($this->auth_override === false &&
+ (!($this->config->item('rest_enable_keys') && $this->_allow === true) ||
+ ($this->config->item('allow_auth_and_keys') === true && $this->_allow === true))) {
+ $rest_auth = strtolower($this->config->item('rest_auth'));
+ switch ($rest_auth) {
+ case 'basic':
+ $this->_prepare_basic_auth();
+ break;
+ case 'digest':
+ $this->_prepare_digest_auth();
+ break;
+ case 'session':
+ $this->_check_php_session();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Does the auth stuff.
+ */
+ private function do_auth($method = false)
+ {
+ // If we don't want to do auth, then just return true
+ if ($method === false) {
+ return true;
+ }
+
+ if (file_exists(__DIR__.'/auth/'.$method.'.php')) {
+ include __DIR__.'/auth/'.$method.'.php';
+ }
+ }
+
+ /**
+ * @param $config_file
+ */
+ private function get_local_config($config_file)
+ {
+ if (file_exists(APPPATH.'config/'.$config_file.'.php')) {
+ $this->load->config($config_file, false);
+ } else {
+ if (file_exists(__DIR__.'/'.$config_file.'.php')) {
+ $config = [];
+ include __DIR__.'/'.$config_file.'.php';
+ foreach ($config as $key => $value) {
+ $this->config->set_item($key, $value);
+ }
+ }
+ }
+ }
+
+ /**
+ * De-constructor.
+ *
+ * @author Chris Kacerguis
+ *
+ * @return void
+ */
+ public function __destruct()
+ {
+ // Log the loading time to the log table
+ if ($this->config->item('rest_enable_logging') === true) {
+ // Get the current timestamp
+ $this->_end_rtime = microtime(true);
+
+ $this->_log_access_time();
+ }
+ }
+
+ /**
+ * Requests are not made to methods directly, the request will be for
+ * an "object". This simply maps the object and method to the correct
+ * Controller method.
+ *
+ * @param string $object_called
+ * @param array $arguments The arguments passed to the controller method
+ *
+ * @throws Exception
+ */
+ public function _remap($object_called, $arguments = [])
+ {
+ // Should we answer if not over SSL?
+ if ($this->config->item('force_https') && $this->request->ssl === false) {
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unsupported'),
+ ], self::HTTP_FORBIDDEN);
+ }
+
+ // Remove the supported format from the function name e.g. index.json => index
+ $object_called = preg_replace('/^(.*)\.(?:'.implode('|', array_keys($this->_supported_formats)).')$/', '$1', $object_called);
+
+ $controller_method = $object_called.'_'.$this->request->method;
+ // Does this method exist? If not, try executing an index method
+ if (!method_exists($this, $controller_method)) {
+ $controller_method = 'index_'.$this->request->method;
+ array_unshift($arguments, $object_called);
+ }
+
+ // Do we want to log this method (if allowed by config)?
+ $log_method = !(isset($this->methods[$controller_method]['log']) && $this->methods[$controller_method]['log'] === false);
+
+ // Use keys for this method?
+ $use_key = !(isset($this->methods[$controller_method]['key']) && $this->methods[$controller_method]['key'] === false);
+
+ // They provided a key, but it wasn't valid, so get them out of here
+ if ($this->config->item('rest_enable_keys') && $use_key && $this->_allow === false) {
+ if ($this->config->item('rest_enable_logging') && $log_method) {
+ $this->_log_request();
+ }
+
+ // fix cross site to option request error
+ if ($this->request->method == 'options') {
+ exit;
+ }
+
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => sprintf($this->lang->line('text_rest_invalid_api_key'), $this->rest->key),
+ ], self::HTTP_FORBIDDEN);
+ }
+
+ // Check to see if this key has access to the requested controller
+ if ($this->config->item('rest_enable_keys') && $use_key && empty($this->rest->key) === false && $this->_check_access() === false) {
+ if ($this->config->item('rest_enable_logging') && $log_method) {
+ $this->_log_request();
+ }
+
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_unauthorized'),
+ ], self::HTTP_UNAUTHORIZED);
+ }
+
+ // Sure it exists, but can they do anything with it?
+ if (!method_exists($this, $controller_method)) {
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unknown_method'),
+ ], self::HTTP_METHOD_NOT_ALLOWED);
+ }
+
+ // Doing key related stuff? Can only do it if they have a key right?
+ if ($this->config->item('rest_enable_keys') && empty($this->rest->key) === false) {
+ // Check the limit
+ if ($this->config->item('rest_enable_limits') && $this->_check_limit($controller_method) === false) {
+ $response = [$this->config->item('rest_status_field_name') => false, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_time_limit')];
+ $this->response($response, self::HTTP_UNAUTHORIZED);
+ }
+
+ // If no level is set use 0, they probably aren't using permissions
+ $level = isset($this->methods[$controller_method]['level']) ? $this->methods[$controller_method]['level'] : 0;
+
+ // If no level is set, or it is lower than/equal to the key's level
+ $authorized = $level <= $this->rest->level;
+ // IM TELLIN!
+ if ($this->config->item('rest_enable_logging') && $log_method) {
+ $this->_log_request($authorized);
+ }
+ if ($authorized === false) {
+ // They don't have good enough perms
+ $response = [$this->config->item('rest_status_field_name') => false, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_permissions')];
+ $this->response($response, self::HTTP_UNAUTHORIZED);
+ }
+ }
+
+ //check request limit by ip without login
+ elseif ($this->config->item('rest_limits_method') == 'IP_ADDRESS' && $this->config->item('rest_enable_limits') && $this->_check_limit($controller_method) === false) {
+ $response = [$this->config->item('rest_status_field_name') => false, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_address_time_limit')];
+ $this->response($response, self::HTTP_UNAUTHORIZED);
+ }
+
+ // No key stuff, but record that stuff is happening
+ elseif ($this->config->item('rest_enable_logging') && $log_method) {
+ $this->_log_request($authorized = true);
+ }
+
+ // Call the controller method and passed arguments
+ try {
+ if ($this->is_valid_request) {
+ call_user_func_array([$this, $controller_method], $arguments);
+ }
+ } catch (Exception $ex) {
+ if ($this->config->item('rest_handle_exceptions') === false) {
+ throw $ex;
+ }
+
+ // If the method doesn't exist, then the error will be caught and an error response shown
+ $_error = &load_class('Exceptions', 'core');
+ $_error->show_exception($ex);
+ }
+ }
+
+ /**
+ * Takes mixed data and optionally a status code, then creates the response.
+ *
+ * @param array|null $data Data to output to the user
+ * @param int|null $http_code HTTP status code
+ * @param bool $continue TRUE to flush the response to the client and continue
+ * running the script; otherwise, exit
+ */
+ public function response($data = null, $http_code = null, $continue = false)
+ {
+ //if profiling enabled then print profiling data
+ $isProfilingEnabled = $this->config->item('enable_profiling');
+ if (!$isProfilingEnabled) {
+ ob_start();
+ // If the HTTP status is not NULL, then cast as an integer
+ if ($http_code !== null) {
+ // So as to be safe later on in the process
+ $http_code = (int) $http_code;
+ }
+
+ // Set the output as NULL by default
+ $output = null;
+
+ // If data is NULL and no HTTP status code provided, then display, error and exit
+ if ($data === null && $http_code === null) {
+ $http_code = self::HTTP_NOT_FOUND;
+ }
+
+ // If data is not NULL and a HTTP status code provided, then continue
+ elseif ($data !== null) {
+ // If the format method exists, call and return the output in that format
+ if (method_exists(Format::class, 'to_'.$this->response->format)) {
+ // CORB protection
+ // First, get the output content.
+ $output = Format::factory($data)->{'to_'.$this->response->format}();
+
+ // Set the format header
+ // Then, check if the client asked for a callback, and if the output contains this callback :
+ if (isset($this->_get_args['callback']) && $this->response->format == 'json' && preg_match('/^'.$this->_get_args['callback'].'/', $output)) {
+ $this->output->set_content_type($this->_supported_formats['jsonp'], strtolower($this->config->item('charset')));
+ } else {
+ $this->output->set_content_type($this->_supported_formats[$this->response->format], strtolower($this->config->item('charset')));
+ }
+
+ // An array must be parsed as a string, so as not to cause an array to string error
+ // Json is the most appropriate form for such a data type
+ if ($this->response->format === 'array') {
+ $output = Format::factory($output)->{'to_json'}();
+ }
+ } else {
+ // If an array or object, then parse as a json, so as to be a 'string'
+ if (is_array($data) || is_object($data)) {
+ $data = Format::factory($data)->{'to_json'}();
+ }
+
+ // Format is not supported, so output the raw data as a string
+ $output = $data;
+ }
+ }
+
+ // If not greater than zero, then set the HTTP status code as 200 by default
+ // Though perhaps 500 should be set instead, for the developer not passing a
+ // correct HTTP status code
+ $http_code > 0 || $http_code = self::HTTP_OK;
+
+ $this->output->set_status_header($http_code);
+
+ // JC: Log response code only if rest logging enabled
+ if ($this->config->item('rest_enable_logging') === true) {
+ $this->_log_response_code($http_code);
+ }
+
+ // Output the data
+ $this->output->set_output($output);
+
+ if ($continue === false) {
+ // Display the data and exit execution
+ $this->output->_display();
+ exit;
+ } else {
+ if (is_callable('fastcgi_finish_request')) {
+ // Terminates connection and returns response to client on PHP-FPM.
+ $this->output->_display();
+ ob_end_flush();
+ fastcgi_finish_request();
+ ignore_user_abort(true);
+ } else {
+ // Legacy compatibility.
+ ob_end_flush();
+ }
+ }
+ ob_end_flush();
+ // Otherwise dump the output automatically
+ } else {
+ echo json_encode($data);
+ }
+ }
+
+ /**
+ * Takes mixed data and optionally a status code, then creates the response
+ * within the buffers of the Output class. The response is sent to the client
+ * lately by the framework, after the current controller's method termination.
+ * All the hooks after the controller's method termination are executable.
+ *
+ * @param array|null $data Data to output to the user
+ * @param int|null $http_code HTTP status code
+ */
+ public function set_response($data = null, $http_code = null)
+ {
+ $this->response($data, $http_code, true);
+ }
+
+ /**
+ * Get the input format e.g. json or xml.
+ *
+ * @return string|null Supported input format; otherwise, NULL
+ */
+ protected function _detect_input_format()
+ {
+ // Get the CONTENT-TYPE value from the SERVER variable
+ $content_type = $this->input->server('CONTENT_TYPE');
+
+ if (empty($content_type) === false) {
+ // If a semi-colon exists in the string, then explode by ; and get the value of where
+ // the current array pointer resides. This will generally be the first element of the array
+ $content_type = (strpos($content_type, ';') !== false ? current(explode(';', $content_type)) : $content_type);
+
+ // Check all formats against the CONTENT-TYPE header
+ foreach ($this->_supported_formats as $type => $mime) {
+ // $type = format e.g. csv
+ // $mime = mime type e.g. application/csv
+
+ // If both the mime types match, then return the format
+ if ($content_type === $mime) {
+ return $type;
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets the default format from the configuration. Fallbacks to 'json'
+ * if the corresponding configuration option $config['rest_default_format']
+ * is missing or is empty.
+ *
+ * @return string The default supported input format
+ */
+ protected function _get_default_output_format()
+ {
+ $default_format = (string) $this->config->item('rest_default_format');
+
+ return $default_format === '' ? 'json' : $default_format;
+ }
+
+ /**
+ * Detect which format should be used to output the data.
+ *
+ * @return mixed|null|string Output format
+ */
+ protected function _detect_output_format()
+ {
+ // Concatenate formats to a regex pattern e.g. \.(csv|json|xml)
+ $pattern = '/\.('.implode('|', array_keys($this->_supported_formats)).')($|\/)/';
+ $matches = [];
+
+ // Check if a file extension is used e.g. http://example.com/api/index.json?param1=param2
+ if (preg_match($pattern, $this->uri->uri_string(), $matches)) {
+ return $matches[1];
+ }
+
+ // Get the format parameter named as 'format'
+ if (isset($this->_get_args['format'])) {
+ $format = strtolower($this->_get_args['format']);
+
+ if (isset($this->_supported_formats[$format]) === true) {
+ return $format;
+ }
+ }
+
+ // Get the HTTP_ACCEPT server variable
+ $http_accept = $this->input->server('HTTP_ACCEPT');
+
+ // Otherwise, check the HTTP_ACCEPT server variable
+ if ($this->config->item('rest_ignore_http_accept') === false && $http_accept !== null) {
+ // Check all formats against the HTTP_ACCEPT header
+ foreach (array_keys($this->_supported_formats) as $format) {
+ // Has this format been requested?
+ if (strpos($http_accept, $format) !== false) {
+ if ($format !== 'html' && $format !== 'xml') {
+ // If not HTML or XML assume it's correct
+ return $format;
+ } elseif ($format === 'html' && strpos($http_accept, 'xml') === false) {
+ // HTML or XML have shown up as a match
+ // If it is truly HTML, it wont want any XML
+ return $format;
+ } elseif ($format === 'xml' && strpos($http_accept, 'html') === false) {
+ // If it is truly XML, it wont want any HTML
+ return $format;
+ }
+ }
+ }
+ }
+
+ // Check if the controller has a default format
+ if (empty($this->rest_format) === false) {
+ return $this->rest_format;
+ }
+
+ // Obtain the default format from the configuration
+ return $this->_get_default_output_format();
+ }
+
+ /**
+ * Get the HTTP request string e.g. get or post.
+ *
+ * @return string|null Supported request method as a lowercase string; otherwise, NULL if not supported
+ */
+ protected function _detect_method()
+ {
+ // Declare a variable to store the method
+ $method = null;
+
+ // Determine whether the 'enable_emulate_request' setting is enabled
+ if ($this->config->item('enable_emulate_request') === true) {
+ $method = $this->input->post('_method');
+ if ($method === null) {
+ $method = $this->input->server('HTTP_X_HTTP_METHOD_OVERRIDE');
+ }
+
+ if ($method !== null) {
+ $method = strtolower($method);
+ }
+ }
+
+ if (empty($method)) {
+ // Get the request method as a lowercase string
+ $method = $this->input->method();
+ }
+
+ return in_array($method, $this->allowed_http_methods) && method_exists($this, '_parse_'.$method) ? $method : 'get';
+ }
+
+ /**
+ * See if the user has provided an API key.
+ *
+ * @return bool
+ */
+ protected function _detect_api_key()
+ {
+ // Get the api key name variable set in the rest config file
+ $api_key_variable = $this->config->item('rest_key_name');
+
+ // Work out the name of the SERVER entry based on config
+ $key_name = 'HTTP_'.strtoupper(str_replace('-', '_', $api_key_variable));
+
+ $this->rest->key = null;
+ $this->rest->level = null;
+ $this->rest->user_id = null;
+ $this->rest->ignore_limits = false;
+
+ // Find the key from server or arguments
+ if (($key = isset($this->_args[$api_key_variable]) ? $this->_args[$api_key_variable] : $this->input->server($key_name))) {
+ if (!($row = $this->rest->db->where($this->config->item('rest_key_column'), $key)->get($this->config->item('rest_keys_table'))->row())) {
+ return false;
+ }
+
+ $this->rest->key = $row->{$this->config->item('rest_key_column')};
+
+ isset($row->user_id) && $this->rest->user_id = $row->user_id;
+ isset($row->level) && $this->rest->level = $row->level;
+ isset($row->ignore_limits) && $this->rest->ignore_limits = $row->ignore_limits;
+
+ $this->_apiuser = $row;
+
+ /*
+ * If "is private key" is enabled, compare the ip address with the list
+ * of valid ip addresses stored in the database
+ */
+ if (empty($row->is_private_key) === false) {
+ // Check for a list of valid ip addresses
+ if (isset($row->ip_addresses)) {
+ // multiple ip addresses must be separated using a comma, explode and loop
+ $list_ip_addresses = explode(',', $row->ip_addresses);
+ $ip_address = $this->input->ip_address();
+ $found_address = false;
+
+ foreach ($list_ip_addresses as $list_ip) {
+ if ($ip_address === trim($list_ip)) {
+ // there is a match, set the the value to TRUE and break out of the loop
+ $found_address = true;
+ break;
+ }
+ }
+
+ return $found_address;
+ } else {
+ // There should be at least one IP address for this private key
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // No key has been sent
+ return false;
+ }
+
+ /**
+ * Preferred return language.
+ *
+ * @return string|null|array The language code
+ */
+ protected function _detect_lang()
+ {
+ $lang = $this->input->server('HTTP_ACCEPT_LANGUAGE');
+ if ($lang === null) {
+ return;
+ }
+
+ // It appears more than one language has been sent using a comma delimiter
+ if (strpos($lang, ',') !== false) {
+ $langs = explode(',', $lang);
+
+ $return_langs = [];
+ foreach ($langs as $lang) {
+ // Remove weight and trim leading and trailing whitespace
+ list($lang) = explode(';', $lang);
+ $return_langs[] = trim($lang);
+ }
+
+ return $return_langs;
+ }
+
+ // Otherwise simply return as a string
+ return $lang;
+ }
+
+ /**
+ * Add the request to the log table.
+ *
+ * @param bool $authorized TRUE the user is authorized; otherwise, FALSE
+ *
+ * @return bool TRUE the data was inserted; otherwise, FALSE
+ */
+ protected function _log_request($authorized = false)
+ {
+ // Insert the request into the log table
+ $is_inserted = $this->rest->db
+ ->insert(
+ $this->config->item('rest_logs_table'),
+ [
+ 'uri' => $this->uri->uri_string(),
+ 'method' => $this->request->method,
+ 'params' => $this->_args ? ($this->config->item('rest_logs_json_params') === true ? json_encode($this->_args) : serialize($this->_args)) : null,
+ 'api_key' => isset($this->rest->key) ? $this->rest->key : '',
+ 'ip_address' => $this->input->ip_address(),
+ 'time' => time(),
+ 'authorized' => $authorized,
+ ]
+ );
+
+ // Get the last insert id to update at a later stage of the request
+ $this->_insert_id = $this->rest->db->insert_id();
+
+ return $is_inserted;
+ }
+
+ /**
+ * Check if the requests to a controller method exceed a limit.
+ *
+ * @param string $controller_method The method being called
+ *
+ * @return bool TRUE the call limit is below the threshold; otherwise, FALSE
+ */
+ protected function _check_limit($controller_method)
+ {
+ // They are special, or it might not even have a limit
+ if (empty($this->rest->ignore_limits) === false) {
+ // Everything is fine
+ return true;
+ }
+
+ $api_key = isset($this->rest->key) ? $this->rest->key : '';
+
+ switch ($this->config->item('rest_limits_method')) {
+ case 'IP_ADDRESS':
+ $api_key = $this->input->ip_address();
+ $limited_uri = 'ip-address:'.$api_key;
+ break;
+
+ case 'API_KEY':
+ $limited_uri = 'api-key:'.$api_key;
+ break;
+
+ case 'METHOD_NAME':
+ $limited_uri = 'method-name:'.$controller_method;
+ break;
+
+ case 'ROUTED_URL':
+ default:
+ $limited_uri = $this->uri->ruri_string();
+ if (strpos(strrev($limited_uri), strrev($this->response->format)) === 0) {
+ $limited_uri = substr($limited_uri, 0, -strlen($this->response->format) - 1);
+ }
+ $limited_uri = 'uri:'.$limited_uri.':'.$this->request->method; // It's good to differentiate GET from PUT
+ break;
+ }
+
+ if (isset($this->methods[$controller_method]['limit']) === false) {
+ // Everything is fine
+ return true;
+ }
+
+ // How many times can you get to this method in a defined time_limit (default: 1 hour)?
+ $limit = $this->methods[$controller_method]['limit'];
+
+ $time_limit = (isset($this->methods[$controller_method]['time']) ? $this->methods[$controller_method]['time'] : 3600); // 3600 = 60 * 60
+
+ // Get data about a keys' usage and limit to one row
+ $result = $this->rest->db
+ ->where('uri', $limited_uri)
+ ->where('api_key', $api_key)
+ ->get($this->config->item('rest_limits_table'))
+ ->row();
+
+ // No calls have been made for this key
+ if ($result === null) {
+ // Create a new row for the following key
+ $this->rest->db->insert($this->config->item('rest_limits_table'), [
+ 'uri' => $limited_uri,
+ 'api_key' => $api_key,
+ 'count' => 1,
+ 'hour_started' => time(),
+ ]);
+ }
+
+ // Been a time limit (or by default an hour) since they called
+ elseif ($result->hour_started < (time() - $time_limit)) {
+ // Reset the started period and count
+ $this->rest->db
+ ->where('uri', $limited_uri)
+ ->where('api_key', $api_key)
+ ->set('hour_started', time())
+ ->set('count', 1)
+ ->update($this->config->item('rest_limits_table'));
+ }
+
+ // They have called within the hour, so lets update
+ else {
+ // The limit has been exceeded
+ if ($result->count >= $limit) {
+ return false;
+ }
+
+ // Increase the count by one
+ $this->rest->db
+ ->where('uri', $limited_uri)
+ ->where('api_key', $api_key)
+ ->set('count', 'count + 1', false)
+ ->update($this->config->item('rest_limits_table'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if there is a specific auth type set for the current class/method/HTTP-method being called.
+ *
+ * @return bool
+ */
+ protected function _auth_override_check()
+ {
+ // Assign the class/method auth type override array from the config
+ $auth_override_class_method = $this->config->item('auth_override_class_method');
+
+ // Check to see if the override array is even populated
+ if (!empty($auth_override_class_method)) {
+ // Check for wildcard flag for rules for classes
+ if (!empty($auth_override_class_method[$this->router->class]['*'])) { // Check for class overrides
+ // No auth override found, prepare nothing but send back a TRUE override flag
+ if ($auth_override_class_method[$this->router->class]['*'] === 'none') {
+ return true;
+ }
+
+ // Basic auth override found, prepare basic
+ if ($auth_override_class_method[$this->router->class]['*'] === 'basic') {
+ $this->_prepare_basic_auth();
+
+ return true;
+ }
+
+ // Digest auth override found, prepare digest
+ if ($auth_override_class_method[$this->router->class]['*'] === 'digest') {
+ $this->_prepare_digest_auth();
+
+ return true;
+ }
+
+ // Session auth override found, check session
+ if ($auth_override_class_method[$this->router->class]['*'] === 'session') {
+ $this->_check_php_session();
+
+ return true;
+ }
+
+ // Whitelist auth override found, check client's ip against config whitelist
+ if ($auth_override_class_method[$this->router->class]['*'] === 'whitelist') {
+ $this->_check_whitelist_auth();
+
+ return true;
+ }
+ }
+
+ // Check to see if there's an override value set for the current class/method being called
+ if (!empty($auth_override_class_method[$this->router->class][$this->router->method])) {
+ // None auth override found, prepare nothing but send back a TRUE override flag
+ if ($auth_override_class_method[$this->router->class][$this->router->method] === 'none') {
+ return true;
+ }
+
+ // Basic auth override found, prepare basic
+ if ($auth_override_class_method[$this->router->class][$this->router->method] === 'basic') {
+ $this->_prepare_basic_auth();
+
+ return true;
+ }
+
+ // Digest auth override found, prepare digest
+ if ($auth_override_class_method[$this->router->class][$this->router->method] === 'digest') {
+ $this->_prepare_digest_auth();
+
+ return true;
+ }
+
+ // Session auth override found, check session
+ if ($auth_override_class_method[$this->router->class][$this->router->method] === 'session') {
+ $this->_check_php_session();
+
+ return true;
+ }
+
+ // Whitelist auth override found, check client's ip against config whitelist
+ if ($auth_override_class_method[$this->router->class][$this->router->method] === 'whitelist') {
+ $this->_check_whitelist_auth();
+
+ return true;
+ }
+ }
+ }
+
+ // Assign the class/method/HTTP-method auth type override array from the config
+ $auth_override_class_method_http = $this->config->item('auth_override_class_method_http');
+
+ // Check to see if the override array is even populated
+ if (!empty($auth_override_class_method_http)) {
+ // check for wildcard flag for rules for classes
+ if (!empty($auth_override_class_method_http[$this->router->class]['*'][$this->request->method])) {
+ // None auth override found, prepare nothing but send back a TRUE override flag
+ if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'none') {
+ return true;
+ }
+
+ // Basic auth override found, prepare basic
+ if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'basic') {
+ $this->_prepare_basic_auth();
+
+ return true;
+ }
+
+ // Digest auth override found, prepare digest
+ if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'digest') {
+ $this->_prepare_digest_auth();
+
+ return true;
+ }
+
+ // Session auth override found, check session
+ if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'session') {
+ $this->_check_php_session();
+
+ return true;
+ }
+
+ // Whitelist auth override found, check client's ip against config whitelist
+ if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'whitelist') {
+ $this->_check_whitelist_auth();
+
+ return true;
+ }
+ }
+
+ // Check to see if there's an override value set for the current class/method/HTTP-method being called
+ if (!empty($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method])) {
+ // None auth override found, prepare nothing but send back a TRUE override flag
+ if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'none') {
+ return true;
+ }
+
+ // Basic auth override found, prepare basic
+ if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'basic') {
+ $this->_prepare_basic_auth();
+
+ return true;
+ }
+
+ // Digest auth override found, prepare digest
+ if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'digest') {
+ $this->_prepare_digest_auth();
+
+ return true;
+ }
+
+ // Session auth override found, check session
+ if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'session') {
+ $this->_check_php_session();
+
+ return true;
+ }
+
+ // Whitelist auth override found, check client's ip against config whitelist
+ if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'whitelist') {
+ $this->_check_whitelist_auth();
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse the GET request arguments.
+ *
+ * @return void
+ */
+ protected function _parse_get()
+ {
+ // Merge both the URI segments and query parameters
+ $this->_get_args = array_merge($this->_get_args, $this->_query_args);
+ }
+
+ /**
+ * Parse the POST request arguments.
+ *
+ * @return void
+ */
+ protected function _parse_post()
+ {
+ $this->_post_args = $_POST;
+
+ if ($this->request->format) {
+ $this->request->body = $this->input->raw_input_stream;
+ }
+ }
+
+ /**
+ * Parse the PUT request arguments.
+ *
+ * @return void
+ */
+ protected function _parse_put()
+ {
+ if ($this->request->format) {
+ $this->request->body = $this->input->raw_input_stream;
+ if ($this->request->format === 'json') {
+ $this->_put_args = json_decode($this->input->raw_input_stream);
+ }
+ } elseif ($this->input->method() === 'put') {
+ // If no file type is provided, then there are probably just arguments
+ $this->_put_args = $this->input->input_stream();
+ }
+ }
+
+ /**
+ * Parse the HEAD request arguments.
+ *
+ * @return void
+ */
+ protected function _parse_head()
+ {
+ // Parse the HEAD variables
+ parse_str(parse_url($this->input->server('REQUEST_URI'), PHP_URL_QUERY), $head);
+
+ // Merge both the URI segments and HEAD params
+ $this->_head_args = array_merge($this->_head_args, $head);
+ }
+
+ /**
+ * Parse the OPTIONS request arguments.
+ *
+ * @return void
+ */
+ protected function _parse_options()
+ {
+ // Parse the OPTIONS variables
+ parse_str(parse_url($this->input->server('REQUEST_URI'), PHP_URL_QUERY), $options);
+
+ // Merge both the URI segments and OPTIONS params
+ $this->_options_args = array_merge($this->_options_args, $options);
+ }
+
+ /**
+ * Parse the PATCH request arguments.
+ *
+ * @return void
+ */
+ protected function _parse_patch()
+ {
+ // It might be a HTTP body
+ if ($this->request->format) {
+ $this->request->body = $this->input->raw_input_stream;
+ } elseif ($this->input->method() === 'patch') {
+ // If no file type is provided, then there are probably just arguments
+ $this->_patch_args = $this->input->input_stream();
+ }
+ }
+
+ /**
+ * Parse the DELETE request arguments.
+ *
+ * @return void
+ */
+ protected function _parse_delete()
+ {
+ // These should exist if a DELETE request
+ if ($this->input->method() === 'delete') {
+ $this->_delete_args = $this->input->input_stream();
+ }
+ }
+
+ /**
+ * Parse the query parameters.
+ *
+ * @return void
+ */
+ protected function _parse_query()
+ {
+ $this->_query_args = $this->input->get();
+ }
+
+ // INPUT FUNCTION --------------------------------------------------------------
+
+ /**
+ * Retrieve a value from a GET request.
+ *
+ * @param null $key Key to retrieve from the GET request
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the GET request; otherwise, NULL
+ */
+ public function get($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ return $this->_get_args;
+ }
+
+ return isset($this->_get_args[$key]) ? $this->_xss_clean($this->_get_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Retrieve a value from a OPTIONS request.
+ *
+ * @param null $key Key to retrieve from the OPTIONS request.
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the OPTIONS request; otherwise, NULL
+ */
+ public function options($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ return $this->_options_args;
+ }
+
+ return isset($this->_options_args[$key]) ? $this->_xss_clean($this->_options_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Retrieve a value from a HEAD request.
+ *
+ * @param null $key Key to retrieve from the HEAD request
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the HEAD request; otherwise, NULL
+ */
+ public function head($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ return $this->_head_args;
+ }
+
+ return isset($this->_head_args[$key]) ? $this->_xss_clean($this->_head_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Retrieve a value from a POST request.
+ *
+ * @param null $key Key to retrieve from the POST request
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the POST request; otherwise, NULL
+ */
+ public function post($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ foreach (new RecursiveIteratorIterator(new RecursiveArrayIterator($this->_post_args), RecursiveIteratorIterator::CATCH_GET_CHILD) as $key => $value) {
+ $this->_post_args[$key] = $this->_xss_clean($this->_post_args[$key], $xss_clean);
+ }
+
+ return $this->_post_args;
+ }
+
+ return isset($this->_post_args[$key]) ? $this->_xss_clean($this->_post_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Retrieve a value from a PUT request.
+ *
+ * @param null $key Key to retrieve from the PUT request
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the PUT request; otherwise, NULL
+ */
+ public function put($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ return $this->_put_args;
+ }
+
+ return isset($this->_put_args[$key]) ? $this->_xss_clean($this->_put_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Retrieve a value from a DELETE request.
+ *
+ * @param null $key Key to retrieve from the DELETE request
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the DELETE request; otherwise, NULL
+ */
+ public function delete($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ return $this->_delete_args;
+ }
+
+ return isset($this->_delete_args[$key]) ? $this->_xss_clean($this->_delete_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Retrieve a value from a PATCH request.
+ *
+ * @param null $key Key to retrieve from the PATCH request
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the PATCH request; otherwise, NULL
+ */
+ public function patch($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ return $this->_patch_args;
+ }
+
+ return isset($this->_patch_args[$key]) ? $this->_xss_clean($this->_patch_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Retrieve a value from the query parameters.
+ *
+ * @param null $key Key to retrieve from the query parameters
+ * If NULL an array of arguments is returned
+ * @param null $xss_clean Whether to apply XSS filtering
+ *
+ * @return array|string|null Value from the query parameters; otherwise, NULL
+ */
+ public function query($key = null, $xss_clean = null)
+ {
+ if ($key === null) {
+ return $this->_query_args;
+ }
+
+ return isset($this->_query_args[$key]) ? $this->_xss_clean($this->_query_args[$key], $xss_clean) : null;
+ }
+
+ /**
+ * Sanitizes data so that Cross Site Scripting Hacks can be
+ * prevented.
+ *
+ * @param string $value Input data
+ * @param bool $xss_clean Whether to apply XSS filtering
+ *
+ * @return string
+ */
+ protected function _xss_clean($value, $xss_clean)
+ {
+ is_bool($xss_clean) || $xss_clean = $this->_enable_xss;
+
+ return $xss_clean === true ? $this->security->xss_clean($value) : $value;
+ }
+
+ /**
+ * Retrieve the validation errors.
+ *
+ * @return array
+ */
+ public function validation_errors()
+ {
+ $string = strip_tags($this->form_validation->error_string());
+
+ return explode(PHP_EOL, trim($string, PHP_EOL));
+ }
+
+ // SECURITY FUNCTIONS ---------------------------------------------------------
+
+ /**
+ * Perform LDAP Authentication.
+ *
+ * @param string $username The username to validate
+ * @param string $password The password to validate
+ *
+ * @return bool
+ */
+ protected function _perform_ldap_auth($username = '', $password = null)
+ {
+ if (empty($username)) {
+ log_message('debug', 'LDAP Auth: failure, empty username');
+
+ return false;
+ }
+
+ log_message('debug', 'LDAP Auth: Loading configuration');
+
+ $this->config->load('ldap', true);
+
+ $ldap = [
+ 'timeout' => $this->config->item('timeout', 'ldap'),
+ 'host' => $this->config->item('server', 'ldap'),
+ 'port' => $this->config->item('port', 'ldap'),
+ 'rdn' => $this->config->item('binduser', 'ldap'),
+ 'pass' => $this->config->item('bindpw', 'ldap'),
+ 'basedn' => $this->config->item('basedn', 'ldap'),
+ ];
+
+ log_message('debug', 'LDAP Auth: Connect to '.(isset($ldap['host']) ? $ldap['host'] : '[ldap not configured]'));
+
+ // Connect to the ldap server
+ $ldapconn = ldap_connect($ldap['host'], $ldap['port']);
+ if ($ldapconn) {
+ log_message('debug', 'Setting timeout to '.$ldap['timeout'].' seconds');
+
+ ldap_set_option($ldapconn, LDAP_OPT_NETWORK_TIMEOUT, $ldap['timeout']);
+
+ log_message('debug', 'LDAP Auth: Binding to '.$ldap['host'].' with dn '.$ldap['rdn']);
+
+ // Binding to the ldap server
+ $ldapbind = ldap_bind($ldapconn, $ldap['rdn'], $ldap['pass']);
+
+ // Verify the binding
+ if ($ldapbind === false) {
+ log_message('error', 'LDAP Auth: bind was unsuccessful');
+
+ return false;
+ }
+
+ log_message('debug', 'LDAP Auth: bind successful');
+ }
+
+ // Search for user
+ if (($res_id = ldap_search($ldapconn, $ldap['basedn'], "uid=$username")) === false) {
+ log_message('error', 'LDAP Auth: User '.$username.' not found in search');
+
+ return false;
+ }
+
+ if (ldap_count_entries($ldapconn, $res_id) !== 1) {
+ log_message('error', 'LDAP Auth: Failure, username '.$username.'found more than once');
+
+ return false;
+ }
+
+ if (($entry_id = ldap_first_entry($ldapconn, $res_id)) === false) {
+ log_message('error', 'LDAP Auth: Failure, entry of search result could not be fetched');
+
+ return false;
+ }
+
+ if (($user_dn = ldap_get_dn($ldapconn, $entry_id)) === false) {
+ log_message('error', 'LDAP Auth: Failure, user-dn could not be fetched');
+
+ return false;
+ }
+
+ // User found, could not authenticate as user
+ if (($link_id = ldap_bind($ldapconn, $user_dn, $password)) === false) {
+ log_message('error', 'LDAP Auth: Failure, username/password did not match: '.$user_dn);
+
+ return false;
+ }
+
+ log_message('debug', 'LDAP Auth: Success '.$user_dn.' authenticated successfully');
+
+ $this->_user_ldap_dn = $user_dn;
+
+ ldap_close($ldapconn);
+
+ return true;
+ }
+
+ /**
+ * Perform Library Authentication - Override this function to change the way the library is called.
+ *
+ * @param string $username The username to validate
+ * @param string $password The password to validate
+ *
+ * @return bool
+ */
+ protected function _perform_library_auth($username = '', $password = null)
+ {
+ if (empty($username)) {
+ log_message('error', 'Library Auth: Failure, empty username');
+
+ return false;
+ }
+
+ $auth_library_class = strtolower($this->config->item('auth_library_class'));
+ $auth_library_function = strtolower($this->config->item('auth_library_function'));
+
+ if (empty($auth_library_class)) {
+ log_message('debug', 'Library Auth: Failure, empty auth_library_class');
+
+ return false;
+ }
+
+ if (empty($auth_library_function)) {
+ log_message('debug', 'Library Auth: Failure, empty auth_library_function');
+
+ return false;
+ }
+
+ if (is_callable([$auth_library_class, $auth_library_function]) === false) {
+ $this->load->library($auth_library_class);
+ }
+
+ return $this->{$auth_library_class}->$auth_library_function($username, $password);
+ }
+
+ /**
+ * Check if the user is logged in.
+ *
+ * @param string $username The user's name
+ * @param bool|string $password The user's password
+ *
+ * @return bool
+ */
+ protected function _check_login($username = null, $password = false)
+ {
+ if (empty($username)) {
+ return false;
+ }
+
+ $auth_source = strtolower($this->config->item('auth_source'));
+ $rest_auth = strtolower($this->config->item('rest_auth'));
+ $valid_logins = $this->config->item('rest_valid_logins');
+
+ if (!$this->config->item('auth_source') && $rest_auth === 'digest') {
+ // For digest we do not have a password passed as argument
+ return md5($username.':'.$this->config->item('rest_realm').':'.(isset($valid_logins[$username]) ? $valid_logins[$username] : ''));
+ }
+
+ if ($password === false) {
+ return false;
+ }
+
+ if ($auth_source === 'ldap') {
+ log_message('debug', "Performing LDAP authentication for $username");
+
+ return $this->_perform_ldap_auth($username, $password);
+ }
+
+ if ($auth_source === 'library') {
+ log_message('debug', "Performing Library authentication for $username");
+
+ return $this->_perform_library_auth($username, $password);
+ }
+
+ if (array_key_exists($username, $valid_logins) === false) {
+ return false;
+ }
+
+ if ($valid_logins[$username] !== $password) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Check to see if the user is logged in with a PHP session key.
+ *
+ * @return void
+ */
+ protected function _check_php_session()
+ {
+ // If whitelist is enabled it has the first chance to kick them out
+ if ($this->config->item('rest_ip_whitelist_enabled')) {
+ $this->_check_whitelist_auth();
+ }
+
+ // Load library session of CodeIgniter
+ $this->load->library('session');
+
+ // Get the auth_source config item
+ $key = $this->config->item('auth_source');
+
+ // If false, then the user isn't logged in
+ if (!$this->session->userdata($key)) {
+ // Display an error response
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unauthorized'),
+ ], self::HTTP_UNAUTHORIZED);
+ }
+ }
+
+ /**
+ * Prepares for basic authentication.
+ *
+ * @return void
+ */
+ protected function _prepare_basic_auth()
+ {
+ // If whitelist is enabled it has the first chance to kick them out
+ if ($this->config->item('rest_ip_whitelist_enabled')) {
+ $this->_check_whitelist_auth();
+ }
+
+ // Returns NULL if the SERVER variables PHP_AUTH_USER and HTTP_AUTHENTICATION don't exist
+ $username = $this->input->server('PHP_AUTH_USER');
+ $http_auth = $this->input->server('HTTP_AUTHENTICATION') ?: $this->input->server('HTTP_AUTHORIZATION');
+
+ $password = null;
+ if ($username !== null) {
+ $password = $this->input->server('PHP_AUTH_PW');
+ } elseif ($http_auth !== null) {
+ // If the authentication header is set as basic, then extract the username and password from
+ // HTTP_AUTHORIZATION e.g. my_username:my_password. This is passed in the .htaccess file
+ if (strpos(strtolower($http_auth), 'basic') === 0) {
+ // Search online for HTTP_AUTHORIZATION workaround to explain what this is doing
+ list($username, $password) = explode(':', base64_decode(substr($this->input->server('HTTP_AUTHORIZATION'), 6)));
+ }
+ }
+
+ // Check if the user is logged into the system
+ if ($this->_check_login($username, $password) === false) {
+ $this->_force_login();
+ }
+ }
+
+ /**
+ * Prepares for digest authentication.
+ *
+ * @return void
+ */
+ protected function _prepare_digest_auth()
+ {
+ // If whitelist is enabled it has the first chance to kick them out
+ if ($this->config->item('rest_ip_whitelist_enabled')) {
+ $this->_check_whitelist_auth();
+ }
+
+ // We need to test which server authentication variable to use,
+ // because the PHP ISAPI module in IIS acts different from CGI
+ $digest_string = $this->input->server('PHP_AUTH_DIGEST');
+ if ($digest_string === null) {
+ $digest_string = $this->input->server('HTTP_AUTHORIZATION');
+ }
+
+ $unique_id = uniqid();
+
+ // The $_SESSION['error_prompted'] variable is used to ask the password
+ // again if none given or if the user enters wrong auth information
+ if (empty($digest_string)) {
+ $this->_force_login($unique_id);
+ }
+
+ // We need to retrieve authentication data from the $digest_string variable
+ $matches = [];
+ preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response)=[\'"]?([^\'",]+)@', $digest_string, $matches);
+ $digest = (empty($matches[1]) || empty($matches[2])) ? [] : array_combine($matches[1], $matches[2]);
+
+ // For digest authentication the library function should return already stored md5(username:restrealm:password) for that username see rest.php::auth_library_function config
+ $username = $this->_check_login($digest['username'], true);
+ if (isset($digest['username']) === false || $username === false) {
+ $this->_force_login($unique_id);
+ }
+
+ $md5 = md5(strtoupper($this->request->method).':'.$digest['uri']);
+ $valid_response = md5($username.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$md5);
+
+ // Check if the string don't compare (case-insensitive)
+ if (strcasecmp($digest['response'], $valid_response) !== 0) {
+ // Display an error response
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_invalid_credentials'),
+ ], self::HTTP_UNAUTHORIZED);
+ }
+ }
+
+ /**
+ * Checks if the client's ip is in the 'rest_ip_blacklist' config and generates a 401 response.
+ *
+ * @return void
+ */
+ protected function _check_blacklist_auth()
+ {
+ // Match an ip address in a blacklist e.g. 127.0.0.0, 0.0.0.0
+ $pattern = sprintf('/(?:,\s*|^)\Q%s\E(?=,\s*|$)/m', $this->input->ip_address());
+
+ // Returns 1, 0 or FALSE (on error only). Therefore implicitly convert 1 to TRUE
+ if (preg_match($pattern, $this->config->item('rest_ip_blacklist'))) {
+ // Display an error response
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_denied'),
+ ], self::HTTP_UNAUTHORIZED);
+ }
+ }
+
+ /**
+ * Check if the client's ip is in the 'rest_ip_whitelist' config and generates a 401 response.
+ *
+ * @return void
+ */
+ protected function _check_whitelist_auth()
+ {
+ $whitelist = explode(',', $this->config->item('rest_ip_whitelist'));
+
+ array_push($whitelist, '127.0.0.1', '0.0.0.0');
+
+ foreach ($whitelist as &$ip) {
+ // As $ip is a reference, trim leading and trailing whitespace, then store the new value
+ // using the reference
+ $ip = trim($ip);
+ }
+
+ if (in_array($this->input->ip_address(), $whitelist) === false) {
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_unauthorized'),
+ ], self::HTTP_UNAUTHORIZED);
+ }
+ }
+
+ /**
+ * Force logging in by setting the WWW-Authenticate header.
+ *
+ * @param string $nonce A server-specified data string which should be uniquely generated
+ * each time
+ *
+ * @return void
+ */
+ protected function _force_login($nonce = '')
+ {
+ $rest_auth = strtolower($this->config->item('rest_auth'));
+ $rest_realm = $this->config->item('rest_realm');
+ if ($rest_auth === 'basic') {
+ // See http://tools.ietf.org/html/rfc2617#page-5
+ header('WWW-Authenticate: Basic realm="'.$rest_realm.'"');
+ } elseif ($rest_auth === 'digest') {
+ // See http://tools.ietf.org/html/rfc2617#page-18
+ header(
+ 'WWW-Authenticate: Digest realm="'.$rest_realm
+ .'", qop="auth", nonce="'.$nonce
+ .'", opaque="'.md5($rest_realm).'"'
+ );
+ }
+
+ if ($this->config->item('strict_api_and_auth') === true) {
+ $this->is_valid_request = false;
+ }
+
+ // Display an error response
+ $this->response([
+ $this->config->item('rest_status_field_name') => false,
+ $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unauthorized'),
+ ], self::HTTP_UNAUTHORIZED);
+ }
+
+ /**
+ * Updates the log table with the total access time.
+ *
+ * @author Chris Kacerguis
+ *
+ * @return bool TRUE log table updated; otherwise, FALSE
+ */
+ protected function _log_access_time()
+ {
+ if ($this->_insert_id == '') {
+ return false;
+ }
+
+ $payload['rtime'] = $this->_end_rtime - $this->_start_rtime;
+
+ return $this->rest->db->update(
+ $this->config->item('rest_logs_table'),
+ $payload,
+ [
+ 'id' => $this->_insert_id,
+ ]
+ );
+ }
+
+ /**
+ * Updates the log table with HTTP response code.
+ *
+ * @author Justin Chen
+ *
+ * @param $http_code int HTTP status code
+ *
+ * @return bool TRUE log table updated; otherwise, FALSE
+ */
+ protected function _log_response_code($http_code)
+ {
+ if ($this->_insert_id == '') {
+ return false;
+ }
+
+ $payload['response_code'] = $http_code;
+
+ return $this->rest->db->update(
+ $this->config->item('rest_logs_table'),
+ $payload,
+ [
+ 'id' => $this->_insert_id,
+ ]
+ );
+ }
+
+ /**
+ * Check to see if the API key has access to the controller and methods.
+ *
+ * @return bool TRUE the API key has access; otherwise, FALSE
+ */
+ protected function _check_access()
+ {
+ // If we don't want to check access, just return TRUE
+ if ($this->config->item('rest_enable_access') === false) {
+ return true;
+ }
+
+ // Fetch controller based on path and controller name
+ $controller = implode(
+ '/',
+ [
+ $this->router->directory,
+ $this->router->class,
+ ]
+ );
+
+ // Remove any double slashes for safety
+ $controller = str_replace('//', '/', $controller);
+
+ //check if the key has all_access
+ $accessRow = $this->rest->db
+ ->where('key', $this->rest->key)
+ ->where('controller', $controller)
+ ->get($this->config->item('rest_access_table'))->row_array();
+
+ if (!empty($accessRow) && !empty($accessRow['all_access'])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks allowed domains, and adds appropriate headers for HTTP access control (CORS).
+ *
+ * @return void
+ */
+ protected function _check_cors()
+ {
+ // Convert the config items into strings
+ $allowed_headers = implode(', ', $this->config->item('allowed_cors_headers'));
+ $allowed_methods = implode(', ', $this->config->item('allowed_cors_methods'));
+
+ // If we want to allow any domain to access the API
+ if ($this->config->item('allow_any_cors_domain') === true) {
+ header('Access-Control-Allow-Origin: *');
+ header('Access-Control-Allow-Headers: '.$allowed_headers);
+ header('Access-Control-Allow-Methods: '.$allowed_methods);
+ } else {
+ // We're going to allow only certain domains access
+ // Store the HTTP Origin header
+ $origin = $this->input->server('HTTP_ORIGIN');
+ if ($origin === null) {
+ $origin = '';
+ }
+
+ // If the origin domain is in the allowed_cors_origins list, then add the Access Control headers
+ if (in_array($origin, $this->config->item('allowed_cors_origins'))) {
+ header('Access-Control-Allow-Origin: '.$origin);
+ header('Access-Control-Allow-Headers: '.$allowed_headers);
+ header('Access-Control-Allow-Methods: '.$allowed_methods);
+ }
+ }
+
+ // If there are headers that should be forced in the CORS check, add them now
+ if (is_array($this->config->item('forced_cors_headers'))) {
+ foreach ($this->config->item('forced_cors_headers') as $header => $value) {
+ header($header.': '.$value);
+ }
+ }
+
+ // If the request HTTP method is 'OPTIONS', kill the response and send it to the client
+ if ($this->input->method() === 'options') {
+ // Load DB if needed for logging
+ if (!isset($this->rest->db) && $this->config->item('rest_enable_logging')) {
+ $this->rest->db = $this->load->database($this->config->item('rest_database_group'), true);
+ }
+ exit;
+ }
+ }
+}
diff --git a/application/plugins/server_alert/media/pgsql_server_alert.sql b/application/plugins/server_alert/media/pgsql_server_alert.sql
index 2ddc73060..d97f0b33e 100644
--- a/application/plugins/server_alert/media/pgsql_server_alert.sql
+++ b/application/plugins/server_alert/media/pgsql_server_alert.sql
@@ -1,4 +1,4 @@
-CREATE TABLE "plugin_server_alert" (
+CREATE TABLE IF NOT EXISTS "plugin_server_alert" (
"id_server_alert" serial PRIMARY KEY,
"alert_name" varchar(100) NOT NULL,
"ip_address" varchar(20) NOT NULL,
@@ -9,4 +9,4 @@ CREATE TABLE "plugin_server_alert" (
"status" text NOT NULL DEFAULT 'true',
"release_code" varchar(8) NOT NULL,
CHECK ("status" IN ('true','false'))
-);
\ No newline at end of file
+);
diff --git a/application/plugins/server_alert/media/sqlite_server_alert.sql b/application/plugins/server_alert/media/sqlite_server_alert.sql
index 0e5dc6577..64ad4c2f0 100644
--- a/application/plugins/server_alert/media/sqlite_server_alert.sql
+++ b/application/plugins/server_alert/media/sqlite_server_alert.sql
@@ -1,4 +1,4 @@
-CREATE TABLE "plugin_server_alert" (
+CREATE TABLE IF NOT EXISTS "plugin_server_alert" (
"id_server_alert" INTEGER PRIMARY KEY AUTOINCREMENT,
"alert_name" VARCHAR(100) NOT NULL,
"ip_address" VARCHAR(20) NOT NULL,
@@ -9,4 +9,4 @@ CREATE TABLE "plugin_server_alert" (
"status" TEXT NOT NULL DEFAULT 'true',
"release_code" VARCHAR(8) NOT NULL,
CHECK ("status" IN ('true','false'))
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_credit/media/pgsql_sms_credit.sql b/application/plugins/sms_credit/media/pgsql_sms_credit.sql
index 7108da750..109c0f5ec 100644
--- a/application/plugins/sms_credit/media/pgsql_sms_credit.sql
+++ b/application/plugins/sms_credit/media/pgsql_sms_credit.sql
@@ -1,4 +1,4 @@
-CREATE TABLE "plugin_sms_credit" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_credit" (
"id_user_credit" serial PRIMARY KEY,
"id_user" integer NOT NULL,
"id_template_credit" integer NOT NULL,
@@ -6,8 +6,8 @@ CREATE TABLE "plugin_sms_credit" (
"valid_end" timestamp(0) WITHOUT time zone NOT NULL
);
-CREATE TABLE "plugin_sms_credit_template" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_credit_template" (
"id_credit_template" serial PRIMARY KEY,
"template_name" varchar(50) NOT NULL,
"sms_numbers" integer NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_credit/media/sqlite_sms_credit.sql b/application/plugins/sms_credit/media/sqlite_sms_credit.sql
index 47b8ea9f7..d2b3ec085 100644
--- a/application/plugins/sms_credit/media/sqlite_sms_credit.sql
+++ b/application/plugins/sms_credit/media/sqlite_sms_credit.sql
@@ -1,4 +1,4 @@
-CREATE TABLE "plugin_sms_credit" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_credit" (
"id_user_credit" INTEGER PRIMARY KEY AUTOINCREMENT,
"id_user" INTEGER NOT NULL,
"id_template_credit" INTEGER NOT NULL,
@@ -6,8 +6,8 @@ CREATE TABLE "plugin_sms_credit" (
"valid_end" DATETIME NOT NULL
);
-CREATE TABLE "plugin_sms_credit_template" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_credit_template" (
"id_credit_template" INTEGER PRIMARY KEY AUTOINCREMENT,
"template_name" VARCHAR(50) NOT NULL,
"sms_numbers" INTEGER NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_member/media/pgsql_sms_member.sql b/application/plugins/sms_member/media/pgsql_sms_member.sql
index 4d89d13b1..dcb77341d 100644
--- a/application/plugins/sms_member/media/pgsql_sms_member.sql
+++ b/application/plugins/sms_member/media/pgsql_sms_member.sql
@@ -1,5 +1,5 @@
-CREATE TABLE "plugin_sms_member" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_member" (
"id_member" serial PRIMARY KEY,
"phone_number" text NOT NULL,
"reg_date" timestamp(0) WITHOUT time zone NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_member/media/sqlite_sms_member.sql b/application/plugins/sms_member/media/sqlite_sms_member.sql
index cfb550067..acb420368 100644
--- a/application/plugins/sms_member/media/sqlite_sms_member.sql
+++ b/application/plugins/sms_member/media/sqlite_sms_member.sql
@@ -1,5 +1,5 @@
-CREATE TABLE "plugin_sms_member" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_member" (
"id_member" INTEGER PRIMARY KEY AUTOINCREMENT,
"phone_number" TEXT NOT NULL,
"reg_date" DATETIME NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_email/media/pgsql_sms_to_email.sql b/application/plugins/sms_to_email/media/pgsql_sms_to_email.sql
index 8e0a5e634..836dd62ef 100644
--- a/application/plugins/sms_to_email/media/pgsql_sms_to_email.sql
+++ b/application/plugins/sms_to_email/media/pgsql_sms_to_email.sql
@@ -1,7 +1,7 @@
-CREATE TABLE "plugin_sms_to_email" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_email" (
"id_user" serial,
"email_forward" text NOT NULL DEFAULT 'false',
"email_id" varchar(64) NOT NULL,
UNIQUE("id_user"),
CHECK ("email_forward" IN ('true','false'))
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_email/media/sqlite_sms_to_email.sql b/application/plugins/sms_to_email/media/sqlite_sms_to_email.sql
index 2faac66da..0dbf80aa2 100644
--- a/application/plugins/sms_to_email/media/sqlite_sms_to_email.sql
+++ b/application/plugins/sms_to_email/media/sqlite_sms_to_email.sql
@@ -1,7 +1,7 @@
-CREATE TABLE "plugin_sms_to_email" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_email" (
"id_user" INTEGER UNIQUE,
"email_forward" TEXT NOT NULL DEFAULT 'false',
"email_id" VARCHAR(64) NOT NULL,
CHECK ("level" IN ('true','false'))
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_twitter/media/pgsql_sms_to_twitter.sql b/application/plugins/sms_to_twitter/media/pgsql_sms_to_twitter.sql
index cf51a4419..3367cc2d7 100644
--- a/application/plugins/sms_to_twitter/media/pgsql_sms_to_twitter.sql
+++ b/application/plugins/sms_to_twitter/media/pgsql_sms_to_twitter.sql
@@ -1,5 +1,5 @@
-CREATE TABLE "plugin_sms_to_twitter" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_twitter" (
"id_user" integer PRIMARY KEY,
"access_token" varchar(255) NOT NULL,
"access_token_secret" varchar(255) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_twitter/media/sqlite_sms_to_twitter.sql b/application/plugins/sms_to_twitter/media/sqlite_sms_to_twitter.sql
index 56d0fa789..302c9dbe2 100644
--- a/application/plugins/sms_to_twitter/media/sqlite_sms_to_twitter.sql
+++ b/application/plugins/sms_to_twitter/media/sqlite_sms_to_twitter.sql
@@ -1,5 +1,5 @@
-CREATE TABLE "plugin_sms_to_twitter" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_twitter" (
"id_user" INTEGER PRIMARY KEY,
"access_token" VARCHAR(255) NOT NULL,
"access_token_secret" VARCHAR(255) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_wordpress/media/pgsql_sms_to_wordpress.sql b/application/plugins/sms_to_wordpress/media/pgsql_sms_to_wordpress.sql
index 2851e0be6..966300f05 100644
--- a/application/plugins/sms_to_wordpress/media/pgsql_sms_to_wordpress.sql
+++ b/application/plugins/sms_to_wordpress/media/pgsql_sms_to_wordpress.sql
@@ -1,6 +1,6 @@
-CREATE TABLE "plugin_sms_to_wordpress" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_wordpress" (
"id_user" integer PRIMARY KEY,
"wp_username" varchar(50) NOT NULL,
"wp_password" varchar(255) NOT NULL,
"wp_url" varchar(100) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_wordpress/media/sqlite_sms_to_wordpress.sql b/application/plugins/sms_to_wordpress/media/sqlite_sms_to_wordpress.sql
index 9246a52c6..fffa8dd1c 100644
--- a/application/plugins/sms_to_wordpress/media/sqlite_sms_to_wordpress.sql
+++ b/application/plugins/sms_to_wordpress/media/sqlite_sms_to_wordpress.sql
@@ -1,6 +1,6 @@
-CREATE TABLE "plugin_sms_to_wordpress" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_wordpress" (
"id_user" INTEGER PRIMARY KEY,
"wp_username" VARCHAR(50) NOT NULL,
"wp_password" VARCHAR(255) NOT NULL,
"wp_url" VARCHAR(100) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_xmpp/media/pgsql_sms_to_xmpp.sql b/application/plugins/sms_to_xmpp/media/pgsql_sms_to_xmpp.sql
index d4ba24723..760e138c0 100644
--- a/application/plugins/sms_to_xmpp/media/pgsql_sms_to_xmpp.sql
+++ b/application/plugins/sms_to_xmpp/media/pgsql_sms_to_xmpp.sql
@@ -1,8 +1,8 @@
-CREATE TABLE "plugin_sms_to_xmpp" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_xmpp" (
"id_user" integer PRIMARY KEY,
"xmpp_host" varchar(100) NOT NULL,
"xmpp_port" varchar(5) NOT NULL,
"xmpp_username" varchar(50) NOT NULL,
"xmpp_password" varchar(255) NOT NULL,
"xmpp_server" varchar(100) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/sms_to_xmpp/media/sqlite_sms_to_xmpp.sql b/application/plugins/sms_to_xmpp/media/sqlite_sms_to_xmpp.sql
index 3f2d34d44..dff802649 100644
--- a/application/plugins/sms_to_xmpp/media/sqlite_sms_to_xmpp.sql
+++ b/application/plugins/sms_to_xmpp/media/sqlite_sms_to_xmpp.sql
@@ -1,8 +1,8 @@
-CREATE TABLE "plugin_sms_to_xmpp" (
+CREATE TABLE IF NOT EXISTS "plugin_sms_to_xmpp" (
"id_user" INTEGER PRIMARY KEY,
"xmpp_host" VARCHAR(100) NOT NULL,
"xmpp_port" VARCHAR(5) NOT NULL,
"xmpp_username" VARCHAR(50) NOT NULL,
"xmpp_password" VARCHAR(255) NOT NULL,
"xmpp_server" VARCHAR(100) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/soap/CREDITS b/application/plugins/soap/CREDITS
deleted file mode 100644
index 55d3a6a2c..000000000
--- a/application/plugins/soap/CREDITS
+++ /dev/null
@@ -1 +0,0 @@
-NuSOAP 0.9.11 https://github.com/f00b4r/nusoap (originally: )
diff --git a/application/plugins/soap/controllers/Api.php b/application/plugins/soap/controllers/Api.php
index c6c3a8c76..b65e8cdb8 100644
--- a/application/plugins/soap/controllers/Api.php
+++ b/application/plugins/soap/controllers/Api.php
@@ -5,7 +5,6 @@
* @License: GNU General Public License
*/
//include_once(APPPATH.'plugins/Plugin_controller.php');
-include_once(dirname(__FILE__).'/../libraries/nusoap.php');
class Api extends MY_Controller {
diff --git a/application/plugins/soap/libraries/nusoap.php b/application/plugins/soap/libraries/nusoap.php
deleted file mode 100644
index 01d251fbf..000000000
--- a/application/plugins/soap/libraries/nusoap.php
+++ /dev/null
@@ -1,8585 +0,0 @@
-
- * @author Scott Nichol
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class nusoap_base
-{
- /**
- * Identification for HTTP headers.
- *
- * @var string
- * @access private
- */
- var $title = 'NuSOAP';
- /**
- * Version for HTTP headers.
- *
- * @var string
- * @access private
- */
- var $version = '0.9.11';
- /**
- * CVS revision for HTTP headers.
- *
- * @var string
- * @access private
- */
- var $revision = '$Revision: 1.123 $';
- /**
- * Current error string (manipulated by getError/setError)
- *
- * @var string
- * @access private
- */
- var $error_str = '';
- /**
- * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment)
- *
- * @var string
- * @access private
- */
- var $debug_str = '';
- /**
- * toggles automatic encoding of special characters as entities
- * (should always be true, I think)
- *
- * @var boolean
- * @access private
- */
- var $charencoding = true;
- /**
- * the debug level for this instance
- *
- * @var integer
- * @access private
- */
- var $debugLevel;
-
- /**
- * set schema version
- *
- * @var string
- * @access public
- */
- var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema';
-
- /**
- * charset encoding for outgoing messages
- *
- * @var string
- * @access public
- */
- var $soap_defencoding = 'ISO-8859-1';
- //var $soap_defencoding = 'UTF-8';
-
- /**
- * namespaces in an array of prefix => uri
- *
- * this is "seeded" by a set of constants, but it may be altered by code
- *
- * @var array
- * @access public
- */
- var $namespaces = array(
- 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/',
- 'xsd' => 'http://www.w3.org/2001/XMLSchema',
- 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
- 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/'
- );
-
- /**
- * namespaces used in the current context, e.g. during serialization
- *
- * @var array
- * @access private
- */
- var $usedNamespaces = array();
-
- /**
- * XML Schema types in an array of uri => (array of xml type => php type)
- * is this legacy yet?
- * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings.
- *
- * @var array
- * @access public
- */
- var $typemap = array(
- 'http://www.w3.org/2001/XMLSchema' => array(
- 'string' => 'string', 'boolean' => 'boolean', 'float' => 'double', 'double' => 'double', 'decimal' => 'double',
- 'duration' => '', 'dateTime' => 'string', 'time' => 'string', 'date' => 'string', 'gYearMonth' => '',
- 'gYear' => '', 'gMonthDay' => '', 'gDay' => '', 'gMonth' => '', 'hexBinary' => 'string', 'base64Binary' => 'string',
- // abstract "any" types
- 'anyType' => 'string', 'anySimpleType' => 'string',
- // derived datatypes
- 'normalizedString' => 'string', 'token' => 'string', 'language' => '', 'NMTOKEN' => '', 'NMTOKENS' => '', 'Name' => '', 'NCName' => '', 'ID' => '',
- 'IDREF' => '', 'IDREFS' => '', 'ENTITY' => '', 'ENTITIES' => '', 'integer' => 'integer', 'nonPositiveInteger' => 'integer',
- 'negativeInteger' => 'integer', 'long' => 'integer', 'int' => 'integer', 'short' => 'integer', 'byte' => 'integer', 'nonNegativeInteger' => 'integer',
- 'unsignedLong' => '', 'unsignedInt' => '', 'unsignedShort' => '', 'unsignedByte' => '', 'positiveInteger' => ''),
- 'http://www.w3.org/2000/10/XMLSchema' => array(
- 'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double',
- 'float' => 'double', 'dateTime' => 'string',
- 'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'),
- 'http://www.w3.org/1999/XMLSchema' => array(
- 'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double',
- 'float' => 'double', 'dateTime' => 'string',
- 'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'),
- 'http://soapinterop.org/xsd' => array('SOAPStruct' => 'struct'),
- 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64' => 'string', 'array' => 'array', 'Array' => 'array'),
- 'http://xml.apache.org/xml-soap' => array('Map')
- );
-
- /**
- * XML entities to convert
- *
- * @var array
- * @access public
- * @deprecated
- * @see expandEntities
- */
- var $xmlEntities = array('quot' => '"', 'amp' => '&',
- 'lt' => '<', 'gt' => '>', 'apos' => "'");
-
- /**
- * HTTP Content-type to be used for SOAP calls and responses
- *
- * @var string
- */
- var $contentType = "text/xml";
-
-
- /**
- * constructor
- *
- * @access public
- */
- function __construct()
- {
- $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
- }
-
- /**
- * gets the global debug level, which applies to future instances
- *
- * @return integer Debug level 0-9, where 0 turns off
- * @access public
- */
- function getGlobalDebugLevel()
- {
- return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'];
- }
-
- /**
- * sets the global debug level, which applies to future instances
- *
- * @param int $level Debug level 0-9, where 0 turns off
- * @access public
- */
- function setGlobalDebugLevel($level)
- {
- $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level;
- }
-
- /**
- * gets the debug level for this instance
- *
- * @return int Debug level 0-9, where 0 turns off
- * @access public
- */
- function getDebugLevel()
- {
- return $this->debugLevel;
- }
-
- /**
- * sets the debug level for this instance
- *
- * @param int $level Debug level 0-9, where 0 turns off
- * @access public
- */
- function setDebugLevel($level)
- {
- $this->debugLevel = $level;
- }
-
- /**
- * adds debug data to the instance debug string with formatting
- *
- * @param string $string debug data
- * @access private
- */
- function debug($string)
- {
- if ($this->debugLevel > 0) {
- $this->appendDebug($this->getmicrotime() . ' ' . get_class($this) . ": $string\n");
- }
- }
-
- /**
- * adds debug data to the instance debug string without formatting
- *
- * @param string $string debug data
- * @access public
- */
- function appendDebug($string)
- {
- if ($this->debugLevel > 0) {
- // it would be nice to use a memory stream here to use
- // memory more efficiently
- $this->debug_str .= $string;
- }
- }
-
- /**
- * clears the current debug data for this instance
- *
- * @access public
- */
- function clearDebug()
- {
- // it would be nice to use a memory stream here to use
- // memory more efficiently
- $this->debug_str = '';
- }
-
- /**
- * gets the current debug data for this instance
- *
- * @return debug data
- * @access public
- */
- function &getDebug()
- {
- // it would be nice to use a memory stream here to use
- // memory more efficiently
- return $this->debug_str;
- }
-
- /**
- * gets the current debug data for this instance as an XML comment
- * this may change the contents of the debug data
- *
- * @return debug data as an XML comment
- * @access public
- */
- function &getDebugAsXMLComment()
- {
- // it would be nice to use a memory stream here to use
- // memory more efficiently
- while (strpos($this->debug_str, '--')) {
- $this->debug_str = str_replace('--', '- -', $this->debug_str);
- }
- $ret = "";
- return $ret;
- }
-
- /**
- * expands entities, e.g. changes '<' to '<'.
- *
- * @param string $val The string in which to expand entities.
- * @access private
- */
- function expandEntities($val)
- {
- if ($this->charencoding) {
- $val = str_replace('&', '&', $val);
- $val = str_replace("'", ''', $val);
- $val = str_replace('"', '"', $val);
- $val = str_replace('<', '<', $val);
- $val = str_replace('>', '>', $val);
- }
- return $val;
- }
-
- /**
- * returns error string if present
- *
- * @return mixed error string or false
- * @access public
- */
- function getError()
- {
- if ($this->error_str != '') {
- return $this->error_str;
- }
- return false;
- }
-
- /**
- * sets error string
- *
- * @return boolean $string error string
- * @access private
- */
- function setError($str)
- {
- $this->error_str = $str;
- }
-
- /**
- * detect if array is a simple array or a struct (associative array)
- *
- * @param mixed $val The PHP array
- * @return string (arraySimple|arrayStruct)
- * @access private
- */
- function isArraySimpleOrStruct($val)
- {
- $keyList = array_keys($val);
- foreach ($keyList as $keyListValue) {
- if (!is_int($keyListValue)) {
- return 'arrayStruct';
- }
- }
- return 'arraySimple';
- }
-
- /**
- * serializes PHP values in accordance w/ section 5. Type information is
- * not serialized if $use == 'literal'.
- *
- * @param mixed $val The value to serialize
- * @param string $name The name (local part) of the XML element
- * @param string $type The XML schema type (local part) for the element
- * @param string $name_ns The namespace for the name of the XML element
- * @param string $type_ns The namespace for the type of the element
- * @param array $attributes The attributes to serialize as name=>value pairs
- * @param string $use The WSDL "use" (encoded|literal)
- * @param boolean $soapval Whether this is called from soapval.
- * @return string The serialized element, possibly with child elements
- * @access public
- */
- function serialize_val($val, $name = false, $type = false, $name_ns = false, $type_ns = false, $attributes = false, $use = 'encoded', $soapval = false)
- {
- $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval");
- $this->appendDebug('value=' . $this->varDump($val));
- $this->appendDebug('attributes=' . $this->varDump($attributes));
-
- if (is_object($val) && get_class($val) == 'soapval' && (!$soapval)) {
- $this->debug("serialize_val: serialize soapval");
- $xml = $val->serialize($use);
- $this->appendDebug($val->getDebug());
- $val->clearDebug();
- $this->debug("serialize_val of soapval returning $xml");
- return $xml;
- }
- // force valid name if necessary
- if (is_numeric($name)) {
- $name = '__numeric_' . $name;
- } elseif (!$name) {
- $name = 'noname';
- }
- // if name has ns, add ns prefix to name
- $xmlns = '';
- if ($name_ns) {
- $prefix = 'nu' . rand(1000, 9999);
- $name = $prefix . ':' . $name;
- $xmlns .= " xmlns:$prefix=\"$name_ns\"";
- }
- // if type is prefixed, create type prefix
- if ($type_ns != '' && $type_ns == $this->namespaces['xsd']) {
- // need to fix this. shouldn't default to xsd if no ns specified
- // w/o checking against typemap
- $type_prefix = 'xsd';
- } elseif ($type_ns) {
- $type_prefix = 'ns' . rand(1000, 9999);
- $xmlns .= " xmlns:$type_prefix=\"$type_ns\"";
- }
- // serialize attributes if present
- $atts = '';
- if ($attributes) {
- foreach ($attributes as $k => $v) {
- $atts .= " $k=\"" . $this->expandEntities($v) . '"';
- }
- }
- // serialize null value
- if (is_null($val)) {
- $this->debug("serialize_val: serialize null");
- if ($use == 'literal') {
- // TODO: depends on minOccurs
- $xml = "<$name$xmlns$atts/>";
- $this->debug("serialize_val returning $xml");
- return $xml;
- } else {
- if (isset($type) && isset($type_prefix)) {
- $type_str = " xsi:type=\"$type_prefix:$type\"";
- } else {
- $type_str = '';
- }
- $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>";
- $this->debug("serialize_val returning $xml");
- return $xml;
- }
- }
- // serialize if an xsd built-in primitive type
- if ($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])) {
- $this->debug("serialize_val: serialize xsd built-in primitive type");
- if (is_bool($val)) {
- if ($type == 'boolean') {
- $val = $val ? 'true' : 'false';
- } elseif (!$val) {
- $val = 0;
- }
- } elseif (is_string($val)) {
- $val = $this->expandEntities($val);
- }
- if ($use == 'literal') {
- $xml = "<$name$xmlns$atts>$val$name>";
- $this->debug("serialize_val returning $xml");
- return $xml;
- } else {
- $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val$name>";
- $this->debug("serialize_val returning $xml");
- return $xml;
- }
- }
- // detect type and serialize
- $xml = '';
- switch (true) {
- case (is_bool($val) || $type == 'boolean'):
- $this->debug("serialize_val: serialize boolean");
- if ($type == 'boolean') {
- $val = $val ? 'true' : 'false';
- } elseif (!$val) {
- $val = 0;
- }
- if ($use == 'literal') {
- $xml .= "<$name$xmlns$atts>$val$name>";
- } else {
- $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val$name>";
- }
- break;
- case (is_int($val) || is_long($val) || $type == 'int'):
- $this->debug("serialize_val: serialize int");
- if ($use == 'literal') {
- $xml .= "<$name$xmlns$atts>$val$name>";
- } else {
- $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val$name>";
- }
- break;
- case (is_float($val) || is_double($val) || $type == 'float'):
- $this->debug("serialize_val: serialize float");
- if ($use == 'literal') {
- $xml .= "<$name$xmlns$atts>$val$name>";
- } else {
- $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val$name>";
- }
- break;
- case (is_string($val) || $type == 'string'):
- $this->debug("serialize_val: serialize string");
- $val = $this->expandEntities($val);
- if ($use == 'literal') {
- $xml .= "<$name$xmlns$atts>$val$name>";
- } else {
- $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val$name>";
- }
- break;
- case is_object($val):
- $this->debug("serialize_val: serialize object");
- if (get_class($val) == 'soapval') {
- $this->debug("serialize_val: serialize soapval object");
- $pXml = $val->serialize($use);
- $this->appendDebug($val->getDebug());
- $val->clearDebug();
- } else {
- if (!$name) {
- $name = get_class($val);
- $this->debug("In serialize_val, used class name $name as element name");
- } else {
- $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val));
- }
- foreach (get_object_vars($val) as $k => $v) {
- $pXml = isset($pXml) ? $pXml . $this->serialize_val($v, $k, false, false, false, false, $use) : $this->serialize_val($v, $k, false, false, false, false, $use);
- }
- }
- if (isset($type) && isset($type_prefix)) {
- $type_str = " xsi:type=\"$type_prefix:$type\"";
- } else {
- $type_str = '';
- }
- if ($use == 'literal') {
- $xml .= "<$name$xmlns$atts>$pXml$name>";
- } else {
- $xml .= "<$name$xmlns$type_str$atts>$pXml$name>";
- }
- break;
- break;
- case (is_array($val) || $type):
- // detect if struct or array
- $valueType = $this->isArraySimpleOrStruct($val);
- if ($valueType == 'arraySimple' || preg_match('/^ArrayOf/', $type)) {
- $this->debug("serialize_val: serialize array");
- $i = 0;
- if (is_array($val) && count($val) > 0) {
- foreach ($val as $v) {
- if (is_object($v) && get_class($v) == 'soapval') {
- $tt_ns = $v->type_ns;
- $tt = $v->type;
- } elseif (is_array($v)) {
- $tt = $this->isArraySimpleOrStruct($v);
- } else {
- $tt = gettype($v);
- }
- $array_types[$tt] = 1;
- // TODO: for literal, the name should be $name
- $xml .= $this->serialize_val($v, 'item', false, false, false, false, $use);
- ++$i;
- }
- if (count($array_types) > 1) {
- $array_typename = 'xsd:anyType';
- } elseif (isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) {
- if ($tt == 'integer') {
- $tt = 'int';
- }
- $array_typename = 'xsd:' . $tt;
- } elseif (isset($tt) && $tt == 'arraySimple') {
- $array_typename = 'SOAP-ENC:Array';
- } elseif (isset($tt) && $tt == 'arrayStruct') {
- $array_typename = 'unnamed_struct_use_soapval';
- } else {
- // if type is prefixed, create type prefix
- if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']) {
- $array_typename = 'xsd:' . $tt;
- } elseif ($tt_ns) {
- $tt_prefix = 'ns' . rand(1000, 9999);
- $array_typename = "$tt_prefix:$tt";
- $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\"";
- } else {
- $array_typename = $tt;
- }
- }
- $array_type = $i;
- if ($use == 'literal') {
- $type_str = '';
- } elseif (isset($type) && isset($type_prefix)) {
- $type_str = " xsi:type=\"$type_prefix:$type\"";
- } else {
- $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[$array_type]\"";
- }
- // empty array
- } else {
- if ($use == 'literal') {
- $type_str = '';
- } elseif (isset($type) && isset($type_prefix)) {
- $type_str = " xsi:type=\"$type_prefix:$type\"";
- } else {
- $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\"";
- }
- }
- // TODO: for array in literal, there is no wrapper here
- $xml = "<$name$xmlns$type_str$atts>" . $xml . "$name>";
- } else {
- // got a struct
- $this->debug("serialize_val: serialize struct");
- if (isset($type) && isset($type_prefix)) {
- $type_str = " xsi:type=\"$type_prefix:$type\"";
- } else {
- $type_str = '';
- }
- if ($use == 'literal') {
- $xml .= "<$name$xmlns$atts>";
- } else {
- $xml .= "<$name$xmlns$type_str$atts>";
- }
- foreach ($val as $k => $v) {
- // Apache Map
- if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') {
- $xml .= '- ';
- $xml .= $this->serialize_val($k, 'key', false, false, false, false, $use);
- $xml .= $this->serialize_val($v, 'value', false, false, false, false, $use);
- $xml .= '
';
- } else {
- $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
- }
- }
- $xml .= "$name>";
- }
- break;
- default:
- $this->debug("serialize_val: serialize unknown");
- $xml .= 'not detected, got ' . gettype($val) . ' for ' . $val;
- break;
- }
- $this->debug("serialize_val returning $xml");
- return $xml;
- }
-
- /**
- * serializes a message
- *
- * @param string $body the XML of the SOAP body
- * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
- * @param array $namespaces optional the namespaces used in generating the body and headers
- * @param string $style optional (rpc|document)
- * @param string $use optional (encoded|literal)
- * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
- * @return string the message
- * @access public
- */
- function serializeEnvelope($body, $headers = false, $namespaces = array(), $style = 'rpc', $use = 'encoded', $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/')
- {
- // TODO: add an option to automatically run utf8_encode on $body and $headers
- // if $this->soap_defencoding is UTF-8. Not doing this automatically allows
- // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1
-
- $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle");
- $this->debug("headers:");
- $this->appendDebug($this->varDump($headers));
- $this->debug("namespaces:");
- $this->appendDebug($this->varDump($namespaces));
-
- // serialize namespaces
- $ns_string = '';
- foreach (array_merge($this->namespaces, $namespaces) as $k => $v) {
- $ns_string .= " xmlns:$k=\"$v\"";
- }
- if ($encodingStyle) {
- $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string";
- }
-
- // serialize headers
- if ($headers) {
- if (is_array($headers)) {
- $xml = '';
- foreach ($headers as $k => $v) {
- if (is_object($v) && get_class($v) == 'soapval') {
- $xml .= $this->serialize_val($v, false, false, false, false, false, $use);
- } else {
- $xml .= $this->serialize_val($v, $k, false, false, false, false, $use);
- }
- }
- $headers = $xml;
- $this->debug("In serializeEnvelope, serialized array of headers to $headers");
- }
- $headers = "" . $headers . " ";
- }
- // serialize envelope
- return
- 'soap_defencoding . '"?' . ">" .
- '" .
- $headers .
- "" .
- $body .
- " " .
- " ";
- }
-
- /**
- * formats a string to be inserted into an HTML stream
- *
- * @param string $str The string to format
- * @return string The formatted string
- * @access public
- * @deprecated
- */
- function formatDump($str)
- {
- $str = htmlspecialchars($str);
- return nl2br($str);
- }
-
- /**
- * contracts (changes namespace to prefix) a qualified name
- *
- * @param string $qname qname
- * @return string contracted qname
- * @access private
- */
- function contractQname($qname)
- {
- // get element namespace
- //$this->xdebug("Contract $qname");
- if (strrpos($qname, ':')) {
- // get unqualified name
- $name = substr($qname, strrpos($qname, ':') + 1);
- // get ns
- $ns = substr($qname, 0, strrpos($qname, ':'));
- $p = $this->getPrefixFromNamespace($ns);
- if ($p) {
- return $p . ':' . $name;
- }
- return $qname;
- } else {
- return $qname;
- }
- }
-
- /**
- * expands (changes prefix to namespace) a qualified name
- *
- * @param string $qname qname
- * @return string expanded qname
- * @access private
- */
- function expandQname($qname)
- {
- // get element prefix
- if (strpos($qname, ':') && !preg_match('/^http:\/\//', $qname)) {
- // get unqualified name
- $name = substr(strstr($qname, ':'), 1);
- // get ns prefix
- $prefix = substr($qname, 0, strpos($qname, ':'));
- if (isset($this->namespaces[$prefix])) {
- return $this->namespaces[$prefix] . ':' . $name;
- } else {
- return $qname;
- }
- } else {
- return $qname;
- }
- }
-
- /**
- * returns the local part of a prefixed string
- * returns the original string, if not prefixed
- *
- * @param string $str The prefixed string
- * @return string The local part
- * @access public
- */
- function getLocalPart($str)
- {
- if ($sstr = strrchr($str, ':')) {
- // get unqualified name
- return substr($sstr, 1);
- } else {
- return $str;
- }
- }
-
- /**
- * returns the prefix part of a prefixed string
- * returns false, if not prefixed
- *
- * @param string $str The prefixed string
- * @return mixed The prefix or false if there is no prefix
- * @access public
- */
- function getPrefix($str)
- {
- if ($pos = strrpos($str, ':')) {
- // get prefix
- return substr($str, 0, $pos);
- }
- return false;
- }
-
- /**
- * pass it a prefix, it returns a namespace
- *
- * @param string $prefix The prefix
- * @return mixed The namespace, false if no namespace has the specified prefix
- * @access public
- */
- function getNamespaceFromPrefix($prefix)
- {
- if (isset($this->namespaces[$prefix])) {
- return $this->namespaces[$prefix];
- }
- //$this->setError("No namespace registered for prefix '$prefix'");
- return false;
- }
-
- /**
- * returns the prefix for a given namespace (or prefix)
- * or false if no prefixes registered for the given namespace
- *
- * @param string $ns The namespace
- * @return mixed The prefix, false if the namespace has no prefixes
- * @access public
- */
- function getPrefixFromNamespace($ns)
- {
- foreach ($this->namespaces as $p => $n) {
- if ($ns == $n || $ns == $p) {
- $this->usedNamespaces[$p] = $n;
- return $p;
- }
- }
- return false;
- }
-
- /**
- * returns the time in ODBC canonical form with microseconds
- *
- * @return string The time in ODBC canonical form with microseconds
- * @access public
- */
- function getmicrotime()
- {
- if (function_exists('gettimeofday')) {
- $tod = gettimeofday();
- $sec = $tod['sec'];
- $usec = $tod['usec'];
- } else {
- $sec = time();
- $usec = 0;
- }
- return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec);
- }
-
- /**
- * Returns a string with the output of var_dump
- *
- * @param mixed $data The variable to var_dump
- * @return string The output of var_dump
- * @access public
- */
- function varDump($data)
- {
- ob_start();
- var_dump($data);
- $ret_val = ob_get_contents();
- ob_end_clean();
- return $ret_val;
- }
-
- /**
- * represents the object as a string
- *
- * @return string
- * @access public
- */
- function __toString()
- {
- return $this->varDump($this);
- }
-}
-
-// XML Schema Datatype Helper Functions
-
-//xsd:dateTime helpers
-
-/**
- * convert unix timestamp to ISO 8601 compliant date string
- *
- * @param int $timestamp Unix time stamp
- * @param boolean $utc Whether the time stamp is UTC or local
- * @return mixed ISO 8601 date string or false
- * @access public
- */
-function timestamp_to_iso8601($timestamp, $utc = true)
-{
- $datestr = date('Y-m-d\TH:i:sO', $timestamp);
- $pos = strrpos($datestr, "+");
- if ($pos === false) {
- $pos = strrpos($datestr, "-");
- }
- if ($pos !== false) {
- if (strlen($datestr) == $pos + 5) {
- $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2);
- }
- }
- if ($utc) {
- $pattern = '/' .
- '([0-9]{4})-' . // centuries & years CCYY-
- '([0-9]{2})-' . // months MM-
- '([0-9]{2})' . // days DD
- 'T' . // separator T
- '([0-9]{2}):' . // hours hh:
- '([0-9]{2}):' . // minutes mm:
- '([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss...
- '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
- '/';
-
- if (preg_match($pattern, $datestr, $regs)) {
- return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]);
- }
- return false;
- } else {
- return $datestr;
- }
-}
-
-/**
- * convert ISO 8601 compliant date string to unix timestamp
- *
- * @param string $datestr ISO 8601 compliant date string
- * @return mixed Unix timestamp (int) or false
- * @access public
- */
-function iso8601_to_timestamp($datestr)
-{
- $pattern = '/' .
- '([0-9]{4})-' . // centuries & years CCYY-
- '([0-9]{2})-' . // months MM-
- '([0-9]{2})' . // days DD
- 'T' . // separator T
- '([0-9]{2}):' . // hours hh:
- '([0-9]{2}):' . // minutes mm:
- '([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss...
- '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's
- '/';
- if (preg_match($pattern, $datestr, $regs)) {
- // not utc
- if ($regs[8] != 'Z') {
- $op = substr($regs[8], 0, 1);
- $h = substr($regs[8], 1, 2);
- $m = substr($regs[8], strlen($regs[8]) - 2, 2);
- if ($op == '-') {
- $regs[4] = $regs[4] + $h;
- $regs[5] = $regs[5] + $m;
- } elseif ($op == '+') {
- $regs[4] = $regs[4] - $h;
- $regs[5] = $regs[5] - $m;
- }
- }
- return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]);
-// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z");
- } else {
- return false;
- }
-}
-
-/**
- * sleeps some number of microseconds
- *
- * @param string $usec the number of microseconds to sleep
- * @access public
- * @deprecated
- */
-function usleepWindows($usec)
-{
- $start = gettimeofday();
-
- do {
- $stop = gettimeofday();
- $timePassed = 1000000 * ($stop['sec'] - $start['sec'])
- + $stop['usec'] - $start['usec'];
- } while ($timePassed < $usec);
-}
-
-
-/**
- * Contains information for a SOAP fault.
- * Mainly used for returning faults from deployed functions
- * in a server instance.
- *
- * @author Dietrich Ayala
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class nusoap_fault extends nusoap_base
-{
- /**
- * The fault code (client|server)
- *
- * @var string
- * @access private
- */
- var $faultcode;
- /**
- * The fault actor
- *
- * @var string
- * @access private
- */
- var $faultactor;
- /**
- * The fault string, a description of the fault
- *
- * @var string
- * @access private
- */
- var $faultstring;
- /**
- * The fault detail, typically a string or array of string
- *
- * @var mixed
- * @access private
- */
- var $faultdetail;
-
- /**
- * constructor
- *
- * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server)
- * @param string $faultactor only used when msg routed between multiple actors
- * @param string $faultstring human readable error message
- * @param mixed $faultdetail detail, typically a string or array of string
- */
- function __construct($faultcode, $faultactor = '', $faultstring = '', $faultdetail = '')
- {
- parent::__construct();
- $this->faultcode = $faultcode;
- $this->faultactor = $faultactor;
- $this->faultstring = $faultstring;
- $this->faultdetail = $faultdetail;
- }
-
- /**
- * serialize a fault
- *
- * @return string The serialization of the fault instance.
- * @access public
- */
- function serialize()
- {
- $ns_string = '';
- foreach ($this->namespaces as $k => $v) {
- $ns_string .= "\n xmlns:$k=\"$v\"";
- }
- $return_msg =
- 'soap_defencoding . '"?>' .
- '\n" .
- '' .
- '' .
- $this->serialize_val($this->faultcode, 'faultcode') .
- $this->serialize_val($this->faultstring, 'faultstring') .
- $this->serialize_val($this->faultactor, 'faultactor') .
- $this->serialize_val($this->faultdetail, 'detail') .
- ' ' .
- ' ' .
- ' ';
- return $return_msg;
- }
-}
-
-
-/**
- * Backward compatibility
- */
-class soap_fault extends nusoap_fault
-{
-}
-
-
-/**
- * parses an XML Schema, allows access to it's data, other utility methods.
- * imperfect, no validation... yet, but quite functional.
- *
- * @author Dietrich Ayala
- * @author Scott Nichol
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class nusoap_xmlschema extends nusoap_base
-{
-
- // files
- var $schema = '';
- var $xml = '';
- // namespaces
- var $enclosingNamespaces;
- // schema info
- var $schemaInfo = array();
- var $schemaTargetNamespace = '';
- // types, elements, attributes defined by the schema
- var $attributes = array();
- var $complexTypes = array();
- var $complexTypeStack = array();
- var $currentComplexType = null;
- var $elements = array();
- var $elementStack = array();
- var $currentElement = null;
- var $simpleTypes = array();
- var $simpleTypeStack = array();
- var $currentSimpleType = null;
- // imports
- var $imports = array();
- // parser vars
- var $parser;
- var $position = 0;
- var $depth = 0;
- var $depth_array = array();
- var $message = array();
- var $defaultNamespace = array();
-
- /**
- * constructor
- *
- * @param string $schema schema document URI
- * @param string $xml xml document URI
- * @param string $namespaces namespaces defined in enclosing XML
- * @access public
- */
- function __construct($schema = '', $xml = '', $namespaces = array())
- {
- parent::__construct();
- $this->debug('nusoap_xmlschema class instantiated, inside constructor');
- // files
- $this->schema = $schema;
- $this->xml = $xml;
-
- // namespaces
- $this->enclosingNamespaces = $namespaces;
- $this->namespaces = array_merge($this->namespaces, $namespaces);
-
- // parse schema file
- if ($schema != '') {
- $this->debug('initial schema file: ' . $schema);
- $this->parseFile($schema, 'schema');
- }
-
- // parse xml file
- if ($xml != '') {
- $this->debug('initial xml file: ' . $xml);
- $this->parseFile($xml, 'xml');
- }
-
- }
-
- /**
- * parse an XML file
- *
- * @param string $xml path/URL to XML file
- * @param string $type (schema | xml)
- * @return boolean
- * @access public
- */
- function parseFile($xml, $type)
- {
- // parse xml file
- if ($xml != "") {
- $xmlStr = @join("", @file($xml));
- if ($xmlStr == "") {
- $msg = 'Error reading XML from ' . $xml;
- $this->setError($msg);
- $this->debug($msg);
- return false;
- } else {
- $this->debug("parsing $xml");
- $this->parseString($xmlStr, $type);
- $this->debug("done parsing $xml");
- return true;
- }
- }
- return false;
- }
-
- /**
- * parse an XML string
- *
- * @param string $xml path or URL
- * @param string $type (schema|xml)
- * @access private
- */
- function parseString($xml, $type)
- {
- // parse xml string
- if ($xml != "") {
-
- // Create an XML parser.
- $this->parser = xml_parser_create();
- // Set the options for parsing the XML data.
- xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
-
- // Set the object for the parser.
- xml_set_object($this->parser, $this);
-
- // Set the element handlers for the parser.
- if ($type == "schema") {
- xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement');
- xml_set_character_data_handler($this->parser, 'schemaCharacterData');
- } elseif ($type == "xml") {
- xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement');
- xml_set_character_data_handler($this->parser, 'xmlCharacterData');
- }
-
- // Parse the XML file.
- if (!xml_parse($this->parser, $xml, true)) {
- // Display an error message.
- $errstr = sprintf('XML error parsing XML schema on line %d: %s',
- xml_get_current_line_number($this->parser),
- xml_error_string(xml_get_error_code($this->parser))
- );
- $this->debug($errstr);
- $this->debug("XML payload:\n" . $xml);
- $this->setError($errstr);
- }
-
- xml_parser_free($this->parser);
- unset($this->parser);
- } else {
- $this->debug('no xml passed to parseString()!!');
- $this->setError('no xml passed to parseString()!!');
- }
- }
-
- /**
- * gets a type name for an unnamed type
- *
- * @param string Element name
- * @return string A type name for an unnamed type
- * @access private
- */
- function CreateTypeName($ename)
- {
- $scope = '';
- for ($i = 0; $i < count($this->complexTypeStack); $i++) {
- $scope .= $this->complexTypeStack[$i] . '_';
- }
- return $scope . $ename . '_ContainedType';
- }
-
- /**
- * start-element handler
- *
- * @param string $parser XML parser object
- * @param string $name element name
- * @param string $attrs associative array of attributes
- * @access private
- */
- function schemaStartElement($parser, $name, $attrs)
- {
-
- // position in the total number of elements, starting from 0
- $pos = $this->position++;
- $depth = $this->depth++;
- // set self as current value for this depth
- $this->depth_array[$depth] = $pos;
- $this->message[$pos] = array('cdata' => '');
- if ($depth > 0) {
- $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
- } else {
- $this->defaultNamespace[$pos] = false;
- }
-
- // get element prefix
- if ($prefix = $this->getPrefix($name)) {
- // get unqualified name
- $name = $this->getLocalPart($name);
- } else {
- $prefix = '';
- }
-
- // loop thru attributes, expanding, and registering namespace declarations
- if (count($attrs) > 0) {
- foreach ($attrs as $k => $v) {
- // if ns declarations, add to class level array of valid namespaces
- if (preg_match('/^xmlns/', $k)) {
- //$this->xdebug("$k: $v");
- //$this->xdebug('ns_prefix: '.$this->getPrefix($k));
- if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
- //$this->xdebug("Add namespace[$ns_prefix] = $v");
- $this->namespaces[$ns_prefix] = $v;
- } else {
- $this->defaultNamespace[$pos] = $v;
- if (!$this->getPrefixFromNamespace($v)) {
- $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
- }
- }
- if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
- $this->XMLSchemaVersion = $v;
- $this->namespaces['xsi'] = $v . '-instance';
- }
- }
- }
- foreach ($attrs as $k => $v) {
- // expand each attribute
- $k = strpos($k, ':') ? $this->expandQname($k) : $k;
- $v = strpos($v, ':') ? $this->expandQname($v) : $v;
- $eAttrs[$k] = $v;
- }
- $attrs = $eAttrs;
- } else {
- $attrs = array();
- }
- // find status, register data
- switch ($name) {
- case 'all': // (optional) compositor content for a complexType
- case 'choice':
- case 'group':
- case 'sequence':
- //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement");
- $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
- //if($name == 'all' || $name == 'sequence'){
- // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
- //}
- break;
- case 'attribute': // complexType attribute
- //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']);
- $this->xdebug("parsing attribute:");
- $this->appendDebug($this->varDump($attrs));
- if (!isset($attrs['form'])) {
- // TODO: handle globals
- $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
- }
- if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
- $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
- if (!strpos($v, ':')) {
- // no namespace in arrayType attribute value...
- if ($this->defaultNamespace[$pos]) {
- // ...so use the default
- $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
- }
- }
- }
- if (isset($attrs['name'])) {
- $this->attributes[$attrs['name']] = $attrs;
- $aname = $attrs['name'];
- } elseif (isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType') {
- if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
- $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
- } else {
- $aname = '';
- }
- } elseif (isset($attrs['ref'])) {
- $aname = $attrs['ref'];
- $this->attributes[$attrs['ref']] = $attrs;
- }
-
- if ($this->currentComplexType) { // This should *always* be
- $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs;
- }
- // arrayType attribute
- if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType') {
- $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
- $prefix = $this->getPrefix($aname);
- if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
- $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
- } else {
- $v = '';
- }
- if (strpos($v, '[,]')) {
- $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
- }
- $v = substr($v, 0, strpos($v, '[')); // clip the []
- if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
- $v = $this->XMLSchemaVersion . ':' . $v;
- }
- $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
- }
- break;
- case 'complexContent': // (optional) content for a complexType
- $this->xdebug("do nothing for element $name");
- break;
- case 'complexType':
- array_push($this->complexTypeStack, $this->currentComplexType);
- if (isset($attrs['name'])) {
- // TODO: what is the scope of named complexTypes that appear
- // nested within other c complexTypes?
- $this->xdebug('processing named complexType ' . $attrs['name']);
- //$this->currentElement = false;
- $this->currentComplexType = $attrs['name'];
- $this->complexTypes[$this->currentComplexType] = $attrs;
- $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
- // This is for constructs like
- //
- //
- //
- //
- //
- if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
- $this->xdebug('complexType is unusual array');
- $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
- } else {
- $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
- }
- } else {
- $name = $this->CreateTypeName($this->currentElement);
- $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
- $this->currentComplexType = $name;
- //$this->currentElement = false;
- $this->complexTypes[$this->currentComplexType] = $attrs;
- $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
- // This is for constructs like
- //
- //
- //
- //
- //
- if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) {
- $this->xdebug('complexType is unusual array');
- $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
- } else {
- $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
- }
- }
- $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
- break;
- case 'element':
- array_push($this->elementStack, $this->currentElement);
- if (!isset($attrs['form'])) {
- if ($this->currentComplexType) {
- $attrs['form'] = $this->schemaInfo['elementFormDefault'];
- } else {
- // global
- $attrs['form'] = 'qualified';
- }
- }
- if (isset($attrs['type'])) {
- $this->xdebug("processing typed element " . $attrs['name'] . " of type " . $attrs['type']);
- if (!$this->getPrefix($attrs['type'])) {
- if ($this->defaultNamespace[$pos]) {
- $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
- $this->xdebug('used default namespace to make type ' . $attrs['type']);
- }
- }
- // This is for constructs like
- //
- //
- //
- //
- //
- if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') {
- $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
- $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
- }
- $this->currentElement = $attrs['name'];
- $ename = $attrs['name'];
- } elseif (isset($attrs['ref'])) {
- $this->xdebug("processing element as ref to " . $attrs['ref']);
- $this->currentElement = "ref to " . $attrs['ref'];
- $ename = $this->getLocalPart($attrs['ref']);
- } else {
- $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
- $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type);
- $this->currentElement = $attrs['name'];
- $attrs['type'] = $this->schemaTargetNamespace . ':' . $type;
- $ename = $attrs['name'];
- }
- if (isset($ename) && $this->currentComplexType) {
- $this->xdebug("add element $ename to complexType $this->currentComplexType");
- $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
- } elseif (!isset($attrs['ref'])) {
- $this->xdebug("add element $ename to elements array");
- $this->elements[$attrs['name']] = $attrs;
- $this->elements[$attrs['name']]['typeClass'] = 'element';
- }
- break;
- case 'enumeration': // restriction value list member
- $this->xdebug('enumeration ' . $attrs['value']);
- if ($this->currentSimpleType) {
- $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
- } elseif ($this->currentComplexType) {
- $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
- }
- break;
- case 'extension': // simpleContent or complexContent type extension
- $this->xdebug('extension ' . $attrs['base']);
- if ($this->currentComplexType) {
- $ns = $this->getPrefix($attrs['base']);
- if ($ns == '') {
- $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
- } else {
- $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
- }
- } else {
- $this->xdebug('no current complexType to set extensionBase');
- }
- break;
- case 'import':
- if (isset($attrs['schemaLocation'])) {
- $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
- $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
- } else {
- $this->xdebug('import namespace ' . $attrs['namespace']);
- $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
- if (!$this->getPrefixFromNamespace($attrs['namespace'])) {
- $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
- }
- }
- break;
- case 'include':
- if (isset($attrs['schemaLocation'])) {
- $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
- $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false);
- } else {
- $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
- }
- break;
- case 'list': // simpleType value list
- $this->xdebug("do nothing for element $name");
- break;
- case 'restriction': // simpleType, simpleContent or complexContent value restriction
- $this->xdebug('restriction ' . $attrs['base']);
- if ($this->currentSimpleType) {
- $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
- } elseif ($this->currentComplexType) {
- $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
- if (strstr($attrs['base'], ':') == ':Array') {
- $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
- }
- }
- break;
- case 'schema':
- $this->schemaInfo = $attrs;
- $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
- if (isset($attrs['targetNamespace'])) {
- $this->schemaTargetNamespace = $attrs['targetNamespace'];
- }
- if (!isset($attrs['elementFormDefault'])) {
- $this->schemaInfo['elementFormDefault'] = 'unqualified';
- }
- if (!isset($attrs['attributeFormDefault'])) {
- $this->schemaInfo['attributeFormDefault'] = 'unqualified';
- }
- break;
- case 'simpleContent': // (optional) content for a complexType
- if ($this->currentComplexType) { // This should *always* be
- $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
- } else {
- $this->xdebug("do nothing for element $name because there is no current complexType");
- }
- break;
- case 'simpleType':
- array_push($this->simpleTypeStack, $this->currentSimpleType);
- if (isset($attrs['name'])) {
- $this->xdebug("processing simpleType for name " . $attrs['name']);
- $this->currentSimpleType = $attrs['name'];
- $this->simpleTypes[$attrs['name']] = $attrs;
- $this->simpleTypes[$attrs['name']]['typeClass'] = 'simpleType';
- $this->simpleTypes[$attrs['name']]['phpType'] = 'scalar';
- } else {
- $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
- $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
- $this->currentSimpleType = $name;
- //$this->currentElement = false;
- $this->simpleTypes[$this->currentSimpleType] = $attrs;
- $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
- }
- break;
- case 'union': // simpleType type list
- $this->xdebug("do nothing for element $name");
- break;
- default:
- $this->xdebug("do not have any logic to process element $name");
- }
- }
-
- /**
- * end-element handler
- *
- * @param string $parser XML parser object
- * @param string $name element name
- * @access private
- */
- function schemaEndElement($parser, $name)
- {
- // bring depth down a notch
- $this->depth--;
- // position of current element is equal to the last value left in depth_array for my depth
- if (isset($this->depth_array[$this->depth])) {
- $pos = $this->depth_array[$this->depth];
- }
- // get element prefix
- if ($prefix = $this->getPrefix($name)) {
- // get unqualified name
- $name = $this->getLocalPart($name);
- } else {
- $prefix = '';
- }
- // move on...
- if ($name == 'complexType') {
- $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)'));
- $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
- $this->currentComplexType = array_pop($this->complexTypeStack);
- //$this->currentElement = false;
- }
- if ($name == 'element') {
- $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)'));
- $this->currentElement = array_pop($this->elementStack);
- }
- if ($name == 'simpleType') {
- $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)'));
- $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
- $this->currentSimpleType = array_pop($this->simpleTypeStack);
- }
- }
-
- /**
- * element content handler
- *
- * @param string $parser XML parser object
- * @param string $data element content
- * @access private
- */
- function schemaCharacterData($parser, $data)
- {
- $pos = $this->depth_array[$this->depth - 1];
- $this->message[$pos]['cdata'] .= $data;
- }
-
- /**
- * serialize the schema
- *
- * @access public
- */
- function serializeSchema()
- {
-
- $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
- $xml = '';
- // imports
- if (sizeof($this->imports) > 0) {
- foreach ($this->imports as $ns => $list) {
- foreach ($list as $ii) {
- if ($ii['location'] != '') {
- $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
- } else {
- $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
- }
- }
- }
- }
- // complex types
- foreach ($this->complexTypes as $typeName => $attrs) {
- $contentStr = '';
- // serialize child elements
- if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) {
- foreach ($attrs['elements'] as $element => $eParts) {
- if (isset($eParts['ref'])) {
- $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n";
- } else {
- $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"";
- foreach ($eParts as $aName => $aValue) {
- // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
- if ($aName != 'name' && $aName != 'type') {
- $contentStr .= " $aName=\"$aValue\"";
- }
- }
- $contentStr .= "/>\n";
- }
- }
- // compositor wraps elements
- if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
- $contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " $schemaPrefix:$attrs[compositor]>\n";
- }
- }
- // attributes
- if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) {
- foreach ($attrs['attrs'] as $attr => $aParts) {
- $contentStr .= " <$schemaPrefix:attribute";
- foreach ($aParts as $a => $v) {
- if ($a == 'ref' || $a == 'type') {
- $contentStr .= " $a=\"" . $this->contractQName($v) . '"';
- } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
- $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
- $contentStr .= ' wsdl:arrayType="' . $this->contractQName($v) . '"';
- } else {
- $contentStr .= " $a=\"$v\"";
- }
- }
- $contentStr .= "/>\n";
- }
- }
- // if restriction
- if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') {
- $contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName($attrs['restrictionBase']) . "\">\n" . $contentStr . " $schemaPrefix:restriction>\n";
- // complex or simple content
- if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)) {
- $contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " $schemaPrefix:complexContent>\n";
- }
- }
- // finalize complex type
- if ($contentStr != '') {
- $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " $schemaPrefix:complexType>\n";
- } else {
- $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
- }
- $xml .= $contentStr;
- }
- // simple types
- if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
- foreach ($this->simpleTypes as $typeName => $eParts) {
- $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName($eParts['type']) . "\">\n";
- if (isset($eParts['enumeration'])) {
- foreach ($eParts['enumeration'] as $e) {
- $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n";
- }
- }
- $xml .= " $schemaPrefix:restriction>\n $schemaPrefix:simpleType>";
- }
- }
- // elements
- if (isset($this->elements) && count($this->elements) > 0) {
- foreach ($this->elements as $element => $eParts) {
- $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n";
- }
- }
- // attributes
- if (isset($this->attributes) && count($this->attributes) > 0) {
- foreach ($this->attributes as $attr => $aParts) {
- $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName($aParts['type']) . "\"\n/>";
- }
- }
- // finish 'er up
- $attr = '';
- foreach ($this->schemaInfo as $k => $v) {
- if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') {
- $attr .= " $k=\"$v\"";
- }
- }
- $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
- foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
- $el .= " xmlns:$nsp=\"$ns\"";
- }
- $xml = $el . ">\n" . $xml . "$schemaPrefix:schema>\n";
- return $xml;
- }
-
- /**
- * adds debug data to the clas level debug string
- *
- * @param string $string debug data
- * @access private
- */
- function xdebug($string)
- {
- $this->debug('<' . $this->schemaTargetNamespace . '> ' . $string);
- }
-
- /**
- * get the PHP type of a user defined type in the schema
- * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
- * returns false if no type exists, or not w/ the given namespace
- * else returns a string that is either a native php type, or 'struct'
- *
- * @param string $type name of defined type
- * @param string $ns namespace of type
- * @return mixed
- * @access public
- * @deprecated
- */
- function getPHPType($type, $ns)
- {
- if (isset($this->typemap[$ns][$type])) {
- //print "found type '$type' and ns $ns in typemap ";
- return $this->typemap[$ns][$type];
- } elseif (isset($this->complexTypes[$type])) {
- //print "getting type '$type' and ns $ns from complexTypes array ";
- return $this->complexTypes[$type]['phpType'];
- }
- return false;
- }
-
- /**
- * returns an associative array of information about a given type
- * returns false if no type exists by the given name
- *
- * For a complexType typeDef = array(
- * 'restrictionBase' => '',
- * 'phpType' => '',
- * 'compositor' => '(sequence|all)',
- * 'elements' => array(), // refs to elements array
- * 'attrs' => array() // refs to attributes array
- * ... and so on (see addComplexType)
- * )
- *
- * For simpleType or element, the array has different keys.
- *
- * @param string $type
- * @return mixed
- * @access public
- * @see addComplexType
- * @see addSimpleType
- * @see addElement
- */
- function getTypeDef($type)
- {
- //$this->debug("in getTypeDef for type $type");
- if (substr($type, -1) == '^') {
- $is_element = 1;
- $type = substr($type, 0, -1);
- } else {
- $is_element = 0;
- }
-
- if ((!$is_element) && isset($this->complexTypes[$type])) {
- $this->xdebug("in getTypeDef, found complexType $type");
- return $this->complexTypes[$type];
- } elseif ((!$is_element) && isset($this->simpleTypes[$type])) {
- $this->xdebug("in getTypeDef, found simpleType $type");
- if (!isset($this->simpleTypes[$type]['phpType'])) {
- // get info for type to tack onto the simple type
- // TODO: can this ever really apply (i.e. what is a simpleType really?)
- $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
- $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':'));
- $etype = $this->getTypeDef($uqType);
- if ($etype) {
- $this->xdebug("in getTypeDef, found type for simpleType $type:");
- $this->xdebug($this->varDump($etype));
- if (isset($etype['phpType'])) {
- $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
- }
- if (isset($etype['elements'])) {
- $this->simpleTypes[$type]['elements'] = $etype['elements'];
- }
- }
- }
- return $this->simpleTypes[$type];
- } elseif (isset($this->elements[$type])) {
- $this->xdebug("in getTypeDef, found element $type");
- if (!isset($this->elements[$type]['phpType'])) {
- // get info for type to tack onto the element
- $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
- $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
- $etype = $this->getTypeDef($uqType);
- if ($etype) {
- $this->xdebug("in getTypeDef, found type for element $type:");
- $this->xdebug($this->varDump($etype));
- if (isset($etype['phpType'])) {
- $this->elements[$type]['phpType'] = $etype['phpType'];
- }
- if (isset($etype['elements'])) {
- $this->elements[$type]['elements'] = $etype['elements'];
- }
- if (isset($etype['extensionBase'])) {
- $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
- }
- } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') {
- $this->xdebug("in getTypeDef, element $type is an XSD type");
- $this->elements[$type]['phpType'] = 'scalar';
- }
- }
- return $this->elements[$type];
- } elseif (isset($this->attributes[$type])) {
- $this->xdebug("in getTypeDef, found attribute $type");
- return $this->attributes[$type];
- } elseif (preg_match('/_ContainedType$/', $type)) {
- $this->xdebug("in getTypeDef, have an untyped element $type");
- $typeDef['typeClass'] = 'simpleType';
- $typeDef['phpType'] = 'scalar';
- $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string';
- return $typeDef;
- }
- $this->xdebug("in getTypeDef, did not find $type");
- return false;
- }
-
- /**
- * returns a sample serialization of a given type, or false if no type by the given name
- *
- * @param string $type name of type
- * @return mixed
- * @access public
- * @deprecated
- */
- function serializeTypeDef($type)
- {
- $str = '';
- //print "in sTD() for type $type ";
- if ($typeDef = $this->getTypeDef($type)) {
- $str .= '<' . $type;
- if (is_array($typeDef['attrs'])) {
- foreach ($typeDef['attrs'] as $attName => $data) {
- $str .= " $attName=\"{type = " . $data['type'] . "}\"";
- }
- }
- $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
- if (count($typeDef['elements']) > 0) {
- $str .= ">";
- foreach ($typeDef['elements'] as $element => $eData) {
- $str .= $this->serializeTypeDef($element);
- }
- $str .= "$type>";
- } elseif ($typeDef['typeClass'] == 'element') {
- $str .= ">$type>";
- } else {
- $str .= "/>";
- }
- return $str;
- }
- return false;
- }
-
- /**
- * returns HTML form elements that allow a user
- * to enter values for creating an instance of the given type.
- *
- * @param string $name name for type instance
- * @param string $type name of type
- * @return string
- * @access public
- * @deprecated
- */
- function typeToForm($name, $type)
- {
- $buffer = '';
- // get typedef
- if ($typeDef = $this->getTypeDef($type)) {
- // if struct
- if ($typeDef['phpType'] == 'struct') {
- $buffer .= '';
- // if array
- } elseif ($typeDef['phpType'] == 'array') {
- $buffer .= '';
- // if scalar
- } else {
- $buffer .= " ";
- }
- } else {
- $buffer .= " ";
- }
- return $buffer;
- }
-
- /**
- * adds a complex type to the schema
- *
- * example: array
- *
- * addType(
- * 'ArrayOfstring',
- * 'complexType',
- * 'array',
- * '',
- * 'SOAP-ENC:Array',
- * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
- * 'xsd:string'
- * );
- *
- * example: PHP associative array ( SOAP Struct )
- *
- * addType(
- * 'SOAPStruct',
- * 'complexType',
- * 'struct',
- * 'all',
- * array('myVar'=> array('name'=>'myVar','type'=>'string')
- * );
- *
- * @param name
- * @param typeClass (complexType|simpleType|attribute)
- * @param phpType : currently supported are array and struct (php assoc array)
- * @param compositor (all|sequence|choice)
- * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
- * @param elements = array ( name = array(name=>'',type=>'') )
- * @param attrs = array(
- * array(
- * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
- * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
- * )
- * )
- * @param arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string)
- * @access public
- * @see getTypeDef
- */
- function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '')
- {
- $this->complexTypes[$name] = array(
- 'name' => $name,
- 'typeClass' => $typeClass,
- 'phpType' => $phpType,
- 'compositor' => $compositor,
- 'restrictionBase' => $restrictionBase,
- 'elements' => $elements,
- 'attrs' => $attrs,
- 'arrayType' => $arrayType
- );
-
- $this->xdebug("addComplexType $name:");
- $this->appendDebug($this->varDump($this->complexTypes[$name]));
- }
-
- /**
- * adds a simple type to the schema
- *
- * @param string $name
- * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
- * @param string $typeClass (should always be simpleType)
- * @param string $phpType (should always be scalar)
- * @param array $enumeration array of values
- * @access public
- * @see nusoap_xmlschema
- * @see getTypeDef
- */
- function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array())
- {
- $this->simpleTypes[$name] = array(
- 'name' => $name,
- 'typeClass' => $typeClass,
- 'phpType' => $phpType,
- 'type' => $restrictionBase,
- 'enumeration' => $enumeration
- );
-
- $this->xdebug("addSimpleType $name:");
- $this->appendDebug($this->varDump($this->simpleTypes[$name]));
- }
-
- /**
- * adds an element to the schema
- *
- * @param array $attrs attributes that must include name and type
- * @see nusoap_xmlschema
- * @access public
- */
- function addElement($attrs)
- {
- if (!$this->getPrefix($attrs['type'])) {
- $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
- }
- $this->elements[$attrs['name']] = $attrs;
- $this->elements[$attrs['name']]['typeClass'] = 'element';
-
- $this->xdebug("addElement " . $attrs['name']);
- $this->appendDebug($this->varDump($this->elements[$attrs['name']]));
- }
-}
-
-/**
- * Backward compatibility
- */
-class XMLSchema extends nusoap_xmlschema
-{
-}
-
-
-/**
- * For creating serializable abstractions of native PHP types. This class
- * allows element name/namespace, XSD type, and XML attributes to be
- * associated with a value. This is extremely useful when WSDL is not
- * used, but is also useful when WSDL is used with polymorphic types, including
- * xsd:anyType and user-defined types.
- *
- * @author Dietrich Ayala
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class soapval extends nusoap_base
-{
- /**
- * The XML element name
- *
- * @var string
- * @access private
- */
- var $name;
- /**
- * The XML type name (string or false)
- *
- * @var mixed
- * @access private
- */
- var $type;
- /**
- * The PHP value
- *
- * @var mixed
- * @access private
- */
- var $value;
- /**
- * The XML element namespace (string or false)
- *
- * @var mixed
- * @access private
- */
- var $element_ns;
- /**
- * The XML type namespace (string or false)
- *
- * @var mixed
- * @access private
- */
- var $type_ns;
- /**
- * The XML element attributes (array or false)
- *
- * @var mixed
- * @access private
- */
- var $attributes;
-
- /**
- * constructor
- *
- * @param string $name optional name
- * @param mixed $type optional type name
- * @param mixed $value optional value
- * @param mixed $element_ns optional namespace of value
- * @param mixed $type_ns optional namespace of type
- * @param mixed $attributes associative array of attributes to add to element serialization
- * @access public
- */
- function __construct($name = 'soapval', $type = false, $value = -1, $element_ns = false, $type_ns = false, $attributes = false)
- {
- parent::__construct();
- $this->name = $name;
- $this->type = $type;
- $this->value = $value;
- $this->element_ns = $element_ns;
- $this->type_ns = $type_ns;
- $this->attributes = $attributes;
- }
-
- /**
- * return serialized value
- *
- * @param string $use The WSDL use value (encoded|literal)
- * @return string XML data
- * @access public
- */
- function serialize($use = 'encoded')
- {
- return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
- }
-
- /**
- * decodes a soapval object into a PHP native type
- *
- * @return mixed
- * @access public
- */
- function decode()
- {
- return $this->value;
- }
-}
-
-
-/**
- * transport class for sending/receiving data via HTTP and HTTPS
- * NOTE: PHP must be compiled with the CURL extension for HTTPS support
- *
- * @author Dietrich Ayala
- * @author Scott Nichol
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class soap_transport_http extends nusoap_base
-{
-
- var $url = '';
- var $uri = '';
- var $digest_uri = '';
- var $scheme = '';
- var $host = '';
- var $port = '';
- var $path = '';
- var $request_method = 'POST';
- var $protocol_version = '1.0';
- var $encoding = '';
- var $outgoing_headers = array();
- var $incoming_headers = array();
- var $incoming_cookies = array();
- var $outgoing_payload = '';
- var $incoming_payload = '';
- var $response_status_line; // HTTP response status line
- var $useSOAPAction = true;
- var $persistentConnection = false;
- var $ch = false; // cURL handle
- var $ch_options = array(); // cURL custom options
- var $use_curl = false; // force cURL use
- var $proxy = null; // proxy information (associative array)
- var $username = '';
- var $password = '';
- var $authtype = '';
- var $digestRequest = array();
- var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
- // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
- // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
- // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
- // passphrase: SSL key password/passphrase
- // certpassword: SSL certificate password
- // verifypeer: default is 1
- // verifyhost: default is 1
-
- /**
- * constructor
- *
- * @param string $url The URL to which to connect
- * @param array $curl_options User-specified cURL options
- * @param boolean $use_curl Whether to try to force cURL use
- * @access public
- */
- function __construct($url, $curl_options = null, $use_curl = false)
- {
- parent::__construct();
- $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
- $this->appendDebug($this->varDump($curl_options));
- $this->setURL($url);
- if (is_array($curl_options)) {
- $this->ch_options = $curl_options;
- }
- $this->use_curl = $use_curl;
- preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
- $this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')');
- }
-
- /**
- * sets a cURL option
- *
- * @param mixed $option The cURL option (always integer?)
- * @param mixed $value The cURL option value
- * @access private
- */
- function setCurlOption($option, $value)
- {
- $this->debug("setCurlOption option=$option, value=");
- $this->appendDebug($this->varDump($value));
- curl_setopt($this->ch, $option, $value);
- }
-
- /**
- * sets an HTTP header
- *
- * @param string $name The name of the header
- * @param string $value The value of the header
- * @access private
- */
- function setHeader($name, $value)
- {
- $this->outgoing_headers[$name] = $value;
- $this->debug("set header $name: $value");
- }
-
- /**
- * unsets an HTTP header
- *
- * @param string $name The name of the header
- * @access private
- */
- function unsetHeader($name)
- {
- if (isset($this->outgoing_headers[$name])) {
- $this->debug("unset header $name");
- unset($this->outgoing_headers[$name]);
- }
- }
-
- /**
- * sets the URL to which to connect
- *
- * @param string $url The URL to which to connect
- * @access private
- */
- function setURL($url)
- {
- $this->url = $url;
-
- $u = parse_url($url);
- foreach ($u as $k => $v) {
- $this->debug("parsed URL $k = $v");
- $this->$k = $v;
- }
-
- // add any GET params to path
- if (isset($u['query']) && $u['query'] != '') {
- $this->path .= '?' . $u['query'];
- }
-
- // set default port
- if (!isset($u['port'])) {
- if ($u['scheme'] == 'https') {
- $this->port = 443;
- } else {
- $this->port = 80;
- }
- }
-
- $this->uri = $this->path;
- $this->digest_uri = $this->uri;
-
- // build headers
- if (!isset($u['port'])) {
- $this->setHeader('Host', $this->host);
- } else {
- $this->setHeader('Host', $this->host . ':' . $this->port);
- }
-
- if (isset($u['user']) && $u['user'] != '') {
- $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
- }
- }
-
- /**
- * gets the I/O method to use
- *
- * @return string I/O method to use (socket|curl|unknown)
- * @access private
- */
- function io_method()
- {
- if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) {
- return 'curl';
- }
- if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) {
- return 'socket';
- }
- return 'unknown';
- }
-
- /**
- * establish an HTTP connection
- *
- * @param integer $timeout set connection timeout in seconds
- * @param integer $response_timeout set response timeout in seconds
- * @return boolean true if connected, false if not
- * @access private
- */
- function connect($connection_timeout = 0, $response_timeout = 30)
- {
- // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
- // "regular" socket.
- // TODO: disabled for now because OpenSSL must be *compiled* in (not just
- // loaded), and until PHP5 stream_get_wrappers is not available.
-// if ($this->scheme == 'https') {
-// if (version_compare(phpversion(), '4.3.0') >= 0) {
-// if (extension_loaded('openssl')) {
-// $this->scheme = 'ssl';
-// $this->debug('Using SSL over OpenSSL');
-// }
-// }
-// }
- $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
- if ($this->io_method() == 'socket') {
- if (!is_array($this->proxy)) {
- $host = $this->host;
- $port = $this->port;
- } else {
- $host = $this->proxy['host'];
- $port = $this->proxy['port'];
- }
-
- // use persistent connection
- if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
- if (!feof($this->fp)) {
- $this->debug('Re-use persistent connection');
- return true;
- }
- fclose($this->fp);
- $this->debug('Closed persistent connection at EOF');
- }
-
- // munge host if using OpenSSL
- if ($this->scheme == 'ssl') {
- $host = 'ssl://' . $host;
- }
- $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
-
- // open socket
- if ($connection_timeout > 0) {
- $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout);
- } else {
- $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
- }
-
- // test pointer
- if (!$this->fp) {
- $msg = 'Couldn\'t open socket connection to server ' . $this->url;
- if ($this->errno) {
- $msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
- } else {
- $msg .= ' prior to connect(). This is often a problem looking up the host name.';
- }
- $this->debug($msg);
- $this->setError($msg);
- return false;
- }
-
- // set response timeout
- $this->debug('set response timeout to ' . $response_timeout);
- socket_set_timeout($this->fp, $response_timeout);
-
- $this->debug('socket connected');
- return true;
- } elseif ($this->io_method() == 'curl') {
- if (!extension_loaded('curl')) {
-// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS');
- $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.');
- return false;
- }
- // Avoid warnings when PHP does not have these options
- if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
- $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
- } else {
- $CURLOPT_CONNECTIONTIMEOUT = 78;
- }
- if (defined('CURLOPT_HTTPAUTH')) {
- $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
- } else {
- $CURLOPT_HTTPAUTH = 107;
- }
- if (defined('CURLOPT_PROXYAUTH')) {
- $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
- } else {
- $CURLOPT_PROXYAUTH = 111;
- }
- if (defined('CURLAUTH_BASIC')) {
- $CURLAUTH_BASIC = CURLAUTH_BASIC;
- } else {
- $CURLAUTH_BASIC = 1;
- }
- if (defined('CURLAUTH_DIGEST')) {
- $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
- } else {
- $CURLAUTH_DIGEST = 2;
- }
- if (defined('CURLAUTH_NTLM')) {
- $CURLAUTH_NTLM = CURLAUTH_NTLM;
- } else {
- $CURLAUTH_NTLM = 8;
- }
-
- $this->debug('connect using cURL');
- // init CURL
- $this->ch = curl_init();
- // set url
- $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
- // add path
- $hostURL .= $this->path;
- $this->setCurlOption(CURLOPT_URL, $hostURL);
- // follow location headers (re-directs)
- if (ini_get('safe_mode') || ini_get('open_basedir')) {
- $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION');
- $this->debug('safe_mode = ');
- $this->appendDebug($this->varDump(ini_get('safe_mode')));
- $this->debug('open_basedir = ');
- $this->appendDebug($this->varDump(ini_get('open_basedir')));
- } else {
- $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
- }
- // ask for headers in the response output
- $this->setCurlOption(CURLOPT_HEADER, 1);
- // ask for the response output as the return value
- $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
- // encode
- // We manage this ourselves through headers and encoding
-// if(function_exists('gzuncompress')){
-// $this->setCurlOption(CURLOPT_ENCODING, 'deflate');
-// }
- // persistent connection
- if ($this->persistentConnection) {
- // I believe the following comment is now bogus, having applied to
- // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
- // The way we send data, we cannot use persistent connections, since
- // there will be some "junk" at the end of our request.
- //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true);
- $this->persistentConnection = false;
- $this->setHeader('Connection', 'close');
- }
- // set timeouts
- if ($connection_timeout != 0) {
- $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
- }
- if ($response_timeout != 0) {
- $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
- }
-
- if ($this->scheme == 'https') {
- $this->debug('set cURL SSL verify options');
- // recent versions of cURL turn on peer/host checking by default,
- // while PHP binaries are not compiled with a default location for the
- // CA cert bundle, so disable peer/host checking.
- //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt');
- $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
- $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
-
- // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
- if ($this->authtype == 'certificate') {
- $this->debug('set cURL certificate options');
- if (isset($this->certRequest['cainfofile'])) {
- $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
- }
- if (isset($this->certRequest['verifypeer'])) {
- $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
- } else {
- $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
- }
- if (isset($this->certRequest['verifyhost'])) {
- $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
- } else {
- $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
- }
- if (isset($this->certRequest['sslcertfile'])) {
- $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
- }
- if (isset($this->certRequest['sslkeyfile'])) {
- $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
- }
- if (isset($this->certRequest['passphrase'])) {
- $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
- }
- if (isset($this->certRequest['certpassword'])) {
- $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
- }
- }
- }
- if ($this->authtype && ($this->authtype != 'certificate')) {
- if ($this->username) {
- $this->debug('set cURL username/password');
- $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
- }
- if ($this->authtype == 'basic') {
- $this->debug('set cURL for Basic authentication');
- $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
- }
- if ($this->authtype == 'digest') {
- $this->debug('set cURL for digest authentication');
- $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
- }
- if ($this->authtype == 'ntlm') {
- $this->debug('set cURL for NTLM authentication');
- $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
- }
- }
- if (is_array($this->proxy)) {
- $this->debug('set cURL proxy options');
- if ($this->proxy['port'] != '') {
- $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port']);
- } else {
- $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
- }
- if ($this->proxy['username'] || $this->proxy['password']) {
- $this->debug('set cURL proxy authentication options');
- $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password']);
- if ($this->proxy['authtype'] == 'basic') {
- $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
- }
- if ($this->proxy['authtype'] == 'ntlm') {
- $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
- }
- }
- }
- $this->debug('cURL connection set up');
- return true;
- } else {
- $this->setError('Unknown scheme ' . $this->scheme);
- $this->debug('Unknown scheme ' . $this->scheme);
- return false;
- }
- }
-
- /**
- * sends the SOAP request and gets the SOAP response via HTTP[S]
- *
- * @param string $data message data
- * @param integer $timeout set connection timeout in seconds
- * @param integer $response_timeout set response timeout in seconds
- * @param array $cookies cookies to send
- * @return string data
- * @access public
- */
- function send($data, $timeout = 0, $response_timeout = 30, $cookies = null)
- {
-
- $this->debug('entered send() with data of length: ' . strlen($data));
-
- $this->tryagain = true;
- $tries = 0;
- while ($this->tryagain) {
- $this->tryagain = false;
- if ($tries++ < 2) {
- // make connnection
- if (!$this->connect($timeout, $response_timeout)) {
- return false;
- }
-
- // send request
- if (!$this->sendRequest($data, $cookies)) {
- return false;
- }
-
- // get response
- $respdata = $this->getResponse();
- } else {
- $this->setError("Too many tries to get an OK response ($this->response_status_line)");
- }
- }
- $this->debug('end of send()');
- return $respdata;
- }
-
-
- /**
- * sends the SOAP request and gets the SOAP response via HTTPS using CURL
- *
- * @param string $data message data
- * @param integer $timeout set connection timeout in seconds
- * @param integer $response_timeout set response timeout in seconds
- * @param array $cookies cookies to send
- * @return string data
- * @access public
- * @deprecated
- */
- function sendHTTPS($data, $timeout = 0, $response_timeout = 30, $cookies = NULL)
- {
- return $this->send($data, $timeout, $response_timeout, $cookies);
- }
-
- /**
- * if authenticating, set user credentials here
- *
- * @param string $username
- * @param string $password
- * @param string $authtype (basic|digest|certificate|ntlm)
- * @param array $digestRequest (keys must be nonce, nc, realm, qop)
- * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
- * @access public
- */
- function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array())
- {
- $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
- $this->appendDebug($this->varDump($digestRequest));
- $this->debug("certRequest=");
- $this->appendDebug($this->varDump($certRequest));
- // cf. RFC 2617
- if ($authtype == 'basic') {
- $this->setHeader('Authorization', 'Basic ' . base64_encode(str_replace(':', '', $username) . ':' . $password));
- } elseif ($authtype == 'digest') {
- if (isset($digestRequest['nonce'])) {
- $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
-
- // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
-
- // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
- $A1 = $username . ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
-
- // H(A1) = MD5(A1)
- $HA1 = md5($A1);
-
- // A2 = Method ":" digest-uri-value
- $A2 = $this->request_method . ':' . $this->digest_uri;
-
- // H(A2)
- $HA2 = md5($A2);
-
- // KD(secret, data) = H(concat(secret, ":", data))
- // if qop == auth:
- // request-digest = <"> < KD ( H(A1), unq(nonce-value)
- // ":" nc-value
- // ":" unq(cnonce-value)
- // ":" unq(qop-value)
- // ":" H(A2)
- // ) <">
- // if qop is missing,
- // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
-
- $unhashedDigest = '';
- $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
- $cnonce = $nonce;
- if ($digestRequest['qop'] != '') {
- $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
- } else {
- $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
- }
-
- $hashedDigest = md5($unhashedDigest);
-
- $opaque = '';
- if (isset($digestRequest['opaque'])) {
- $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
- }
-
- $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
- }
- } elseif ($authtype == 'certificate') {
- $this->certRequest = $certRequest;
- $this->debug('Authorization header not set for certificate');
- } elseif ($authtype == 'ntlm') {
- // do nothing
- $this->debug('Authorization header not set for ntlm');
- }
- $this->username = $username;
- $this->password = $password;
- $this->authtype = $authtype;
- $this->digestRequest = $digestRequest;
- }
-
- /**
- * set the soapaction value
- *
- * @param string $soapaction
- * @access public
- */
- function setSOAPAction($soapaction)
- {
- $this->setHeader('SOAPAction', '"' . $soapaction . '"');
- }
-
- /**
- * use http encoding
- *
- * @param string $enc encoding style. supported values: gzip, deflate, or both
- * @access public
- */
- function setEncoding($enc = 'gzip, deflate')
- {
- if (function_exists('gzdeflate')) {
- $this->protocol_version = '1.1';
- $this->setHeader('Accept-Encoding', $enc);
- if (!isset($this->outgoing_headers['Connection'])) {
- $this->setHeader('Connection', 'close');
- $this->persistentConnection = false;
- }
- // deprecated as of PHP 5.3.0
- //set_magic_quotes_runtime(0);
- $this->encoding = $enc;
- }
- }
-
- /**
- * set proxy info here
- *
- * @param string $proxyhost use an empty string to remove proxy
- * @param string $proxyport
- * @param string $proxyusername
- * @param string $proxypassword
- * @param string $proxyauthtype (basic|ntlm)
- * @access public
- */
- function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic')
- {
- if ($proxyhost) {
- $this->proxy = array(
- 'host' => $proxyhost,
- 'port' => $proxyport,
- 'username' => $proxyusername,
- 'password' => $proxypassword,
- 'authtype' => $proxyauthtype
- );
- if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
- $this->setHeader('Proxy-Authorization', ' Basic ' . base64_encode($proxyusername . ':' . $proxypassword));
- }
- } else {
- $this->debug('remove proxy');
- $proxy = null;
- unsetHeader('Proxy-Authorization');
- }
- }
-
-
- /**
- * Test if the given string starts with a header that is to be skipped.
- * Skippable headers result from chunked transfer and proxy requests.
- *
- * @param string $data The string to check.
- * @returns boolean Whether a skippable header was found.
- * @access private
- */
- function isSkippableCurlHeader(&$data)
- {
- $skipHeaders = array('HTTP/1.1 100',
- 'HTTP/1.0 301',
- 'HTTP/1.1 301',
- 'HTTP/1.0 302',
- 'HTTP/1.1 302',
- 'HTTP/1.0 401',
- 'HTTP/1.1 401',
- 'HTTP/1.0 200 Connection established');
- foreach ($skipHeaders as $hd) {
- $prefix = substr($data, 0, strlen($hd));
- if ($prefix == $hd) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * decode a string that is encoded w/ "chunked' transfer encoding
- * as defined in RFC2068 19.4.6
- *
- * @param string $buffer
- * @param string $lb
- * @returns string
- * @access public
- * @deprecated
- */
- function decodeChunked($buffer, $lb)
- {
- // length := 0
- $length = 0;
- $new = '';
-
- // read chunk-size, chunk-extension (if any) and CRLF
- // get the position of the linebreak
- $chunkend = strpos($buffer, $lb);
- if ($chunkend == false) {
- $this->debug('no linebreak found in decodeChunked');
- return $new;
- }
- $temp = substr($buffer, 0, $chunkend);
- $chunk_size = hexdec(trim($temp));
- $chunkstart = $chunkend + strlen($lb);
- // while (chunk-size > 0) {
- while ($chunk_size > 0) {
- $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
- $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size);
-
- // Just in case we got a broken connection
- if ($chunkend == false) {
- $chunk = substr($buffer, $chunkstart);
- // append chunk-data to entity-body
- $new .= $chunk;
- $length += strlen($chunk);
- break;
- }
-
- // read chunk-data and CRLF
- $chunk = substr($buffer, $chunkstart, $chunkend - $chunkstart);
- // append chunk-data to entity-body
- $new .= $chunk;
- // length := length + chunk-size
- $length += strlen($chunk);
- // read chunk-size and CRLF
- $chunkstart = $chunkend + strlen($lb);
-
- $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
- if ($chunkend == false) {
- break; //Just in case we got a broken connection
- }
- $temp = substr($buffer, $chunkstart, $chunkend - $chunkstart);
- $chunk_size = hexdec(trim($temp));
- $chunkstart = $chunkend;
- }
- return $new;
- }
-
- /**
- * Writes the payload, including HTTP headers, to $this->outgoing_payload.
- *
- * @param string $data HTTP body
- * @param string $cookie_str data for HTTP Cookie header
- * @return void
- * @access private
- */
- function buildPayload($data, $cookie_str = '')
- {
- // Note: for cURL connections, $this->outgoing_payload is ignored,
- // as is the Content-Length header, but these are still created as
- // debugging guides.
-
- // add content-length header
- if ($this->request_method != 'GET') {
- $this->setHeader('Content-Length', strlen($data));
- }
-
- // start building outgoing payload:
- if ($this->proxy) {
- $uri = $this->url;
- } else {
- $uri = $this->uri;
- }
- $req = "$this->request_method $uri HTTP/$this->protocol_version";
- $this->debug("HTTP request: $req");
- $this->outgoing_payload = "$req\r\n";
-
- // loop thru headers, serializing
- foreach ($this->outgoing_headers as $k => $v) {
- $hdr = $k . ': ' . $v;
- $this->debug("HTTP header: $hdr");
- $this->outgoing_payload .= "$hdr\r\n";
- }
-
- // add any cookies
- if ($cookie_str != '') {
- $hdr = 'Cookie: ' . $cookie_str;
- $this->debug("HTTP header: $hdr");
- $this->outgoing_payload .= "$hdr\r\n";
- }
-
- // header/body separator
- $this->outgoing_payload .= "\r\n";
-
- // add data
- $this->outgoing_payload .= $data;
- }
-
- /**
- * sends the SOAP request via HTTP[S]
- *
- * @param string $data message data
- * @param array $cookies cookies to send
- * @return boolean true if OK, false if problem
- * @access private
- */
- function sendRequest($data, $cookies = null)
- {
- // build cookie string
- $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https')));
-
- // build payload
- $this->buildPayload($data, $cookie_str);
-
- if ($this->io_method() == 'socket') {
- // send payload
- if (!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
- $this->setError('couldn\'t write message data to socket');
- $this->debug('couldn\'t write message data to socket');
- return false;
- }
- $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
- return true;
- } elseif ($this->io_method() == 'curl') {
- // set payload
- // cURL does say this should only be the verb, and in fact it
- // turns out that the URI and HTTP version are appended to this, which
- // some servers refuse to work with (so we no longer use this method!)
- //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload);
- $curl_headers = array();
- foreach ($this->outgoing_headers as $k => $v) {
- if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') {
- $this->debug("Skip cURL header $k: $v");
- } else {
- $curl_headers[] = "$k: $v";
- }
- }
- if ($cookie_str != '') {
- $curl_headers[] = 'Cookie: ' . $cookie_str;
- }
- $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
- $this->debug('set cURL HTTP headers');
- if ($this->request_method == "POST") {
- $this->setCurlOption(CURLOPT_POST, 1);
- $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
- $this->debug('set cURL POST data');
- } else {
- }
- // insert custom user-set cURL options
- foreach ($this->ch_options as $key => $val) {
- $this->setCurlOption($key, $val);
- }
-
- $this->debug('set cURL payload');
- return true;
- }
- }
-
- /**
- * gets the SOAP response via HTTP[S]
- *
- * @return string the response (also sets member variables like incoming_payload)
- * @access private
- */
- function getResponse()
- {
- $this->incoming_payload = '';
-
- if ($this->io_method() == 'socket') {
- // loop until headers have been retrieved
- $data = '';
- while (!isset($lb)) {
-
- // We might EOF during header read.
- if (feof($this->fp)) {
- $this->incoming_payload = $data;
- $this->debug('found no headers before EOF after length ' . strlen($data));
- $this->debug("received before EOF:\n" . $data);
- $this->setError('server failed to send headers');
- return false;
- }
-
- $tmp = fgets($this->fp, 256);
- $tmplen = strlen($tmp);
- $this->debug("read line of $tmplen bytes: " . trim($tmp));
-
- if ($tmplen == 0) {
- $this->incoming_payload = $data;
- $this->debug('socket read of headers timed out after length ' . strlen($data));
- $this->debug("read before timeout: " . $data);
- $this->setError('socket read of headers timed out');
- return false;
- }
-
- $data .= $tmp;
- $pos = strpos($data, "\r\n\r\n");
- if ($pos > 1) {
- $lb = "\r\n";
- } else {
- $pos = strpos($data, "\n\n");
- if ($pos > 1) {
- $lb = "\n";
- }
- }
- // remove 100 headers
- if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) {
- unset($lb);
- $data = '';
- }//
- }
- // store header data
- $this->incoming_payload .= $data;
- $this->debug('found end of headers after length ' . strlen($data));
- // process headers
- $header_data = trim(substr($data, 0, $pos));
- $header_array = explode($lb, $header_data);
- $this->incoming_headers = array();
- $this->incoming_cookies = array();
- foreach ($header_array as $header_line) {
- $arr = explode(':', $header_line, 2);
- if (count($arr) > 1) {
- $header_name = strtolower(trim($arr[0]));
- $this->incoming_headers[$header_name] = trim($arr[1]);
- if ($header_name == 'set-cookie') {
- // TODO: allow multiple cookies from parseCookie
- $cookie = $this->parseCookie(trim($arr[1]));
- if ($cookie) {
- $this->incoming_cookies[] = $cookie;
- $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
- } else {
- $this->debug('did not find cookie in ' . trim($arr[1]));
- }
- }
- } elseif (isset($header_name)) {
- // append continuation line to previous header
- $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
- }
- }
-
- // loop until msg has been received
- if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') {
- $content_length = 2147483647; // ignore any content-length header
- $chunked = true;
- $this->debug("want to read chunked content");
- } elseif (isset($this->incoming_headers['content-length'])) {
- $content_length = $this->incoming_headers['content-length'];
- $chunked = false;
- $this->debug("want to read content of length $content_length");
- } else {
- $content_length = 2147483647;
- $chunked = false;
- $this->debug("want to read content to EOF");
- }
- $data = '';
- do {
- if ($chunked) {
- $tmp = fgets($this->fp, 256);
- $tmplen = strlen($tmp);
- $this->debug("read chunk line of $tmplen bytes");
- if ($tmplen == 0) {
- $this->incoming_payload = $data;
- $this->debug('socket read of chunk length timed out after length ' . strlen($data));
- $this->debug("read before timeout:\n" . $data);
- $this->setError('socket read of chunk length timed out');
- return false;
- }
- $content_length = hexdec(trim($tmp));
- $this->debug("chunk length $content_length");
- }
- $strlen = 0;
- while (($strlen < $content_length) && (!feof($this->fp))) {
- $readlen = min(8192, $content_length - $strlen);
- $tmp = fread($this->fp, $readlen);
- $tmplen = strlen($tmp);
- $this->debug("read buffer of $tmplen bytes");
- if (($tmplen == 0) && (!feof($this->fp))) {
- $this->incoming_payload = $data;
- $this->debug('socket read of body timed out after length ' . strlen($data));
- $this->debug("read before timeout:\n" . $data);
- $this->setError('socket read of body timed out');
- return false;
- }
- $strlen += $tmplen;
- $data .= $tmp;
- }
- if ($chunked && ($content_length > 0)) {
- $tmp = fgets($this->fp, 256);
- $tmplen = strlen($tmp);
- $this->debug("read chunk terminator of $tmplen bytes");
- if ($tmplen == 0) {
- $this->incoming_payload = $data;
- $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
- $this->debug("read before timeout:\n" . $data);
- $this->setError('socket read of chunk terminator timed out');
- return false;
- }
- }
- } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
- if (feof($this->fp)) {
- $this->debug('read to EOF');
- }
- $this->debug('read body of length ' . strlen($data));
- $this->incoming_payload .= $data;
- $this->debug('received a total of ' . strlen($this->incoming_payload) . ' bytes of data from server');
-
- // close filepointer
- if (
- (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') ||
- (!$this->persistentConnection) || feof($this->fp)
- ) {
- fclose($this->fp);
- $this->fp = false;
- $this->debug('closed socket');
- }
-
- // connection was closed unexpectedly
- if ($this->incoming_payload == '') {
- $this->setError('no response from server');
- return false;
- }
-
- // decode transfer-encoding
-// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){
-// if(!$data = $this->decodeChunked($data, $lb)){
-// $this->setError('Decoding of chunked data failed');
-// return false;
-// }
- //print "\nde-chunked:\n---------------\n$data\n\n---------------\n ";
- // set decoded payload
-// $this->incoming_payload = $header_data.$lb.$lb.$data;
-// }
-
- } elseif ($this->io_method() == 'curl') {
- // send and receive
- $this->debug('send and receive with cURL');
- $this->incoming_payload = curl_exec($this->ch);
- $data = $this->incoming_payload;
-
- $cErr = curl_error($this->ch);
- if ($cErr != '') {
- $err = 'cURL ERROR: ' . curl_errno($this->ch) . ': ' . $cErr . ' ';
- // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
- foreach (curl_getinfo($this->ch) as $k => $v) {
- if (is_array($v)) {
- $this->debug("$k: " . json_encode($v));
- } else {
- $this->debug("$k: $v ");
- }
- }
- $this->debug($err);
- $this->setError($err);
- curl_close($this->ch);
- return false;
- } else {
- //echo '';
- //var_dump(curl_getinfo($this->ch));
- //echo ' ';
- }
- // close curl
- $this->debug('No cURL error, closing cURL');
- curl_close($this->ch);
-
- // try removing skippable headers
- $savedata = $data;
- while ($this->isSkippableCurlHeader($data)) {
- $this->debug("Found HTTP header to skip");
- if ($pos = strpos($data, "\r\n\r\n")) {
- $data = ltrim(substr($data, $pos));
- } elseif ($pos = strpos($data, "\n\n")) {
- $data = ltrim(substr($data, $pos));
- }
- }
-
- if ($data == '') {
- // have nothing left; just remove 100 header(s)
- $data = $savedata;
- while (preg_match('/^HTTP\/1.1 100/', $data)) {
- if ($pos = strpos($data, "\r\n\r\n")) {
- $data = ltrim(substr($data, $pos));
- } elseif ($pos = strpos($data, "\n\n")) {
- $data = ltrim(substr($data, $pos));
- }
- }
- }
-
- // separate content from HTTP headers
- if ($pos = strpos($data, "\r\n\r\n")) {
- $lb = "\r\n";
- } elseif ($pos = strpos($data, "\n\n")) {
- $lb = "\n";
- } else {
- $this->debug('no proper separation of headers and document');
- $this->setError('no proper separation of headers and document');
- return false;
- }
- $header_data = trim(substr($data, 0, $pos));
- $header_array = explode($lb, $header_data);
- $data = ltrim(substr($data, $pos));
- $this->debug('found proper separation of headers and document');
- $this->debug('cleaned data, stringlen: ' . strlen($data));
- // clean headers
- foreach ($header_array as $header_line) {
- $arr = explode(':', $header_line, 2);
- if (count($arr) > 1) {
- $header_name = strtolower(trim($arr[0]));
- $this->incoming_headers[$header_name] = trim($arr[1]);
- if ($header_name == 'set-cookie') {
- // TODO: allow multiple cookies from parseCookie
- $cookie = $this->parseCookie(trim($arr[1]));
- if ($cookie) {
- $this->incoming_cookies[] = $cookie;
- $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
- } else {
- $this->debug('did not find cookie in ' . trim($arr[1]));
- }
- }
- } elseif (isset($header_name)) {
- // append continuation line to previous header
- $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
- }
- }
- }
-
- $this->response_status_line = $header_array[0];
- $arr = explode(' ', $this->response_status_line, 3);
- $http_version = $arr[0];
- $http_status = intval($arr[1]);
- $http_reason = count($arr) > 2 ? $arr[2] : '';
-
- // see if we need to resend the request with http digest authentication
- if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
- $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
- $this->setURL($this->incoming_headers['location']);
- $this->tryagain = true;
- return false;
- }
-
- // see if we need to resend the request with http digest authentication
- if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
- $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
- if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) {
- $this->debug('Server wants digest authentication');
- // remove "Digest " from our elements
- $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
-
- // parse elements into array
- $digestElements = explode(',', $digestString);
- foreach ($digestElements as $val) {
- $tempElement = explode('=', trim($val), 2);
- $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]);
- }
-
- // should have (at least) qop, realm, nonce
- if (isset($digestRequest['nonce'])) {
- $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
- $this->tryagain = true;
- return false;
- }
- }
- $this->debug('HTTP authentication failed');
- $this->setError('HTTP authentication failed');
- return false;
- }
-
- if (
- ($http_status >= 300 && $http_status <= 307) ||
- ($http_status >= 400 && $http_status <= 417) ||
- ($http_status >= 501 && $http_status <= 505)
- ) {
- $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
- return false;
- }
-
- // decode content-encoding
- if (isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != '') {
- if (strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip') {
- // if decoding works, use it. else assume data wasn't gzencoded
- if (function_exists('gzinflate')) {
- //$timer->setMarker('starting decoding of gzip/deflated content');
- // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
- // this means there are no Zlib headers, although there should be
- $this->debug('The gzinflate function exists');
- $datalen = strlen($data);
- if ($this->incoming_headers['content-encoding'] == 'deflate') {
- if ($degzdata = @gzinflate($data)) {
- $data = $degzdata;
- $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
- if (strlen($data) < $datalen) {
- // test for the case that the payload has been compressed twice
- $this->debug('The inflated payload is smaller than the gzipped one; try again');
- if ($degzdata = @gzinflate($data)) {
- $data = $degzdata;
- $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
- }
- }
- } else {
- $this->debug('Error using gzinflate to inflate the payload');
- $this->setError('Error using gzinflate to inflate the payload');
- }
- } elseif ($this->incoming_headers['content-encoding'] == 'gzip') {
- if ($degzdata = @gzinflate(substr($data, 10))) { // do our best
- $data = $degzdata;
- $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
- if (strlen($data) < $datalen) {
- // test for the case that the payload has been compressed twice
- $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
- if ($degzdata = @gzinflate(substr($data, 10))) {
- $data = $degzdata;
- $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
- }
- }
- } else {
- $this->debug('Error using gzinflate to un-gzip the payload');
- $this->setError('Error using gzinflate to un-gzip the payload');
- }
- }
- //$timer->setMarker('finished decoding of gzip/deflated content');
- //print "\nde-inflated:\n---------------\n$data\n-------------\n ";
- // set decoded payload
- $this->incoming_payload = $header_data . $lb . $lb . $data;
- } else {
- $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
- $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
- }
- } else {
- $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
- $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
- }
- } else {
- $this->debug('No Content-Encoding header');
- }
-
- if (strlen($data) == 0) {
- $this->debug('no data after headers!');
- $this->setError('no data present after HTTP headers');
- return false;
- }
-
- return $data;
- }
-
- /**
- * sets the content-type for the SOAP message to be sent
- *
- * @param string $type the content type, MIME style
- * @param mixed $charset character set used for encoding (or false)
- * @access public
- */
- function setContentType($type, $charset = false)
- {
- $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
- }
-
- /**
- * specifies that an HTTP persistent connection should be used
- *
- * @return boolean whether the request was honored by this method.
- * @access public
- */
- function usePersistentConnection()
- {
- if (isset($this->outgoing_headers['Accept-Encoding'])) {
- return false;
- }
- $this->protocol_version = '1.1';
- $this->persistentConnection = true;
- $this->setHeader('Connection', 'Keep-Alive');
- return true;
- }
-
- /**
- * parse an incoming Cookie into it's parts
- *
- * @param string $cookie_str content of cookie
- * @return array with data of that cookie
- * @access private
- */
- /*
- * TODO: allow a Set-Cookie string to be parsed into multiple cookies
- */
- function parseCookie($cookie_str)
- {
- $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
- $data = preg_split('/;/', $cookie_str);
- $value_str = $data[0];
-
- $cookie_param = 'domain=';
- $start = strpos($cookie_str, $cookie_param);
- if ($start > 0) {
- $domain = substr($cookie_str, $start + strlen($cookie_param));
- $domain = substr($domain, 0, strpos($domain, ';'));
- } else {
- $domain = '';
- }
-
- $cookie_param = 'expires=';
- $start = strpos($cookie_str, $cookie_param);
- if ($start > 0) {
- $expires = substr($cookie_str, $start + strlen($cookie_param));
- $expires = substr($expires, 0, strpos($expires, ';'));
- } else {
- $expires = '';
- }
-
- $cookie_param = 'path=';
- $start = strpos($cookie_str, $cookie_param);
- if ($start > 0) {
- $path = substr($cookie_str, $start + strlen($cookie_param));
- $path = substr($path, 0, strpos($path, ';'));
- } else {
- $path = '/';
- }
-
- $cookie_param = ';secure;';
- if (strpos($cookie_str, $cookie_param) !== false) {
- $secure = true;
- } else {
- $secure = false;
- }
-
- $sep_pos = strpos($value_str, '=');
-
- if ($sep_pos) {
- $name = substr($value_str, 0, $sep_pos);
- $value = substr($value_str, $sep_pos + 1);
- $cookie = array('name' => $name,
- 'value' => $value,
- 'domain' => $domain,
- 'path' => $path,
- 'expires' => $expires,
- 'secure' => $secure
- );
- return $cookie;
- }
- return false;
- }
-
- /**
- * sort out cookies for the current request
- *
- * @param array $cookies array with all cookies
- * @param boolean $secure is the send-content secure or not?
- * @return string for Cookie-HTTP-Header
- * @access private
- */
- function getCookiesForRequest($cookies, $secure = false)
- {
- $cookie_str = '';
- if ((!is_null($cookies)) && (is_array($cookies))) {
- foreach ($cookies as $cookie) {
- if (!is_array($cookie)) {
- continue;
- }
- $this->debug("check cookie for validity: " . $cookie['name'] . '=' . $cookie['value']);
- if ((isset($cookie['expires'])) && (!empty($cookie['expires']))) {
- if (strtotime($cookie['expires']) <= time()) {
- $this->debug('cookie has expired');
- continue;
- }
- }
- if ((isset($cookie['domain'])) && (!empty($cookie['domain']))) {
- $domain = preg_quote($cookie['domain']);
- if (!preg_match("'.*$domain$'i", $this->host)) {
- $this->debug('cookie has different domain');
- continue;
- }
- }
- if ((isset($cookie['path'])) && (!empty($cookie['path']))) {
- $path = preg_quote($cookie['path']);
- if (!preg_match("'^$path.*'i", $this->path)) {
- $this->debug('cookie is for a different path');
- continue;
- }
- }
- if ((!$secure) && (isset($cookie['secure'])) && ($cookie['secure'])) {
- $this->debug('cookie is secure, transport is not');
- continue;
- }
- $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
- $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
- }
- }
- return $cookie_str;
- }
-}
-
-
-/**
- *
- * nusoap_server allows the user to create a SOAP server
- * that is capable of receiving messages and returning responses
- *
- * @author Dietrich Ayala
- * @author Scott Nichol
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class nusoap_server extends nusoap_base
-{
- /**
- * HTTP headers of request
- *
- * @var array
- * @access private
- */
- var $headers = array();
- /**
- * HTTP request
- *
- * @var string
- * @access private
- */
- var $request = '';
- /**
- * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
- *
- * @var string
- * @access public
- */
- var $requestHeaders = '';
- /**
- * SOAP Headers from request (parsed)
- *
- * @var mixed
- * @access public
- */
- var $requestHeader = null;
- /**
- * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
- *
- * @var string
- * @access public
- */
- var $document = '';
- /**
- * SOAP payload for request (text)
- *
- * @var string
- * @access public
- */
- var $requestSOAP = '';
- /**
- * requested method namespace URI
- *
- * @var string
- * @access private
- */
- var $methodURI = '';
- /**
- * name of method requested
- *
- * @var string
- * @access private
- */
- var $methodname = '';
- /**
- * method parameters from request
- *
- * @var array
- * @access private
- */
- var $methodparams = array();
- /**
- * SOAP Action from request
- *
- * @var string
- * @access private
- */
- var $SOAPAction = '';
- /**
- * character set encoding of incoming (request) messages
- *
- * @var string
- * @access public
- */
- var $xml_encoding = '';
- /**
- * toggles whether the parser decodes element content w/ utf8_decode()
- *
- * @var boolean
- * @access public
- */
- var $decode_utf8 = true;
-
- /**
- * HTTP headers of response
- *
- * @var array
- * @access public
- */
- var $outgoing_headers = array();
- /**
- * HTTP response
- *
- * @var string
- * @access private
- */
- var $response = '';
- /**
- * SOAP headers for response (text or array of soapval or associative array)
- *
- * @var mixed
- * @access public
- */
- var $responseHeaders = '';
- /**
- * SOAP payload for response (text)
- *
- * @var string
- * @access private
- */
- var $responseSOAP = '';
- /**
- * method return value to place in response
- *
- * @var mixed
- * @access private
- */
- var $methodreturn = false;
- /**
- * whether $methodreturn is a string of literal XML
- *
- * @var boolean
- * @access public
- */
- var $methodreturnisliteralxml = false;
- /**
- * SOAP fault for response (or false)
- *
- * @var mixed
- * @access private
- */
- var $fault = false;
- /**
- * text indication of result (for debugging)
- *
- * @var string
- * @access private
- */
- var $result = 'successful';
-
- /**
- * assoc array of operations => opData; operations are added by the register()
- * method or by parsing an external WSDL definition
- *
- * @var array
- * @access private
- */
- var $operations = array();
- /**
- * wsdl instance (if one)
- *
- * @var mixed
- * @access private
- */
- var $wsdl = false;
- /**
- * URL for WSDL (if one)
- *
- * @var mixed
- * @access private
- */
- var $externalWSDLURL = false;
- /**
- * whether to append debug to response as XML comment
- *
- * @var boolean
- * @access public
- */
- var $debug_flag = false;
-
-
- /**
- * constructor
- * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
- *
- * @param mixed $wsdl file path or URL (string), or wsdl instance (object)
- * @access public
- */
- function __construct($wsdl = false)
- {
- parent::__construct();
- // turn on debugging?
- global $debug;
- global $HTTP_SERVER_VARS;
-
- if (isset($_SERVER)) {
- $this->debug("_SERVER is defined:");
- $this->appendDebug($this->varDump($_SERVER));
- } elseif (isset($HTTP_SERVER_VARS)) {
- $this->debug("HTTP_SERVER_VARS is defined:");
- $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
- } else {
- $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined.");
- }
-
- if (isset($debug)) {
- $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
- $this->debug_flag = $debug;
- } elseif (isset($_SERVER['QUERY_STRING'])) {
- $qs = explode('&', $_SERVER['QUERY_STRING']);
- foreach ($qs as $v) {
- if (substr($v, 0, 6) == 'debug=') {
- $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1");
- $this->debug_flag = substr($v, 6);
- }
- }
- } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
- $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
- foreach ($qs as $v) {
- if (substr($v, 0, 6) == 'debug=') {
- $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2");
- $this->debug_flag = substr($v, 6);
- }
- }
- }
-
- // wsdl
- if ($wsdl) {
- $this->debug("In nusoap_server, WSDL is specified");
- if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) {
- $this->wsdl = $wsdl;
- $this->externalWSDLURL = $this->wsdl->wsdl;
- $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
- } else {
- $this->debug('Create wsdl from ' . $wsdl);
- $this->wsdl = new wsdl($wsdl);
- $this->externalWSDLURL = $wsdl;
- }
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- if ($err = $this->wsdl->getError()) {
- die('WSDL ERROR: ' . $err);
- }
- }
- }
-
- /**
- * processes request and returns response
- *
- * @param string $data usually is the value of $HTTP_RAW_POST_DATA
- * @access public
- */
- function service($data)
- {
- global $HTTP_SERVER_VARS;
-
- if (isset($_SERVER['REQUEST_METHOD'])) {
- $rm = $_SERVER['REQUEST_METHOD'];
- } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
- $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
- } else {
- $rm = '';
- }
-
- if (isset($_SERVER['QUERY_STRING'])) {
- $qs = $_SERVER['QUERY_STRING'];
- } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
- $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
- } else {
- $qs = '';
- }
- $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
-
- if ($rm == 'POST') {
- $this->debug("In service, invoke the request");
- $this->parse_request($data);
- if (!$this->fault) {
- $this->invoke_method();
- }
- if (!$this->fault) {
- $this->serialize_return();
- }
- $this->send_response();
- } elseif (preg_match('/wsdl/', $qs)) {
- $this->debug("In service, this is a request for WSDL");
- if ($this->externalWSDLURL) {
- if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL
- $this->debug("In service, re-direct for WSDL");
- header('Location: ' . $this->externalWSDLURL);
- } else { // assume file
- $this->debug("In service, use file passthru for WSDL");
- header("Content-Type: text/xml\r\n");
- $pos = strpos($this->externalWSDLURL, "file://");
- if ($pos === false) {
- $filename = $this->externalWSDLURL;
- } else {
- $filename = substr($this->externalWSDLURL, $pos + 7);
- }
- $fp = fopen($this->externalWSDLURL, 'r');
- fpassthru($fp);
- }
- } elseif ($this->wsdl) {
- $this->debug("In service, serialize WSDL");
- header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
- print $this->wsdl->serialize($this->debug_flag);
- if ($this->debug_flag) {
- $this->debug('wsdl:');
- $this->appendDebug($this->varDump($this->wsdl));
- print $this->getDebugAsXMLComment();
- }
- } else {
- $this->debug("In service, there is no WSDL");
- header("Content-Type: text/html; charset=ISO-8859-1\r\n");
- print "This service does not provide WSDL";
- }
- } elseif ($this->wsdl) {
- $this->debug("In service, return Web description");
- print $this->wsdl->webDescription();
- } else {
- $this->debug("In service, no Web description");
- header("Content-Type: text/html; charset=ISO-8859-1\r\n");
- print "This service does not provide a Web description";
- }
- }
-
- /**
- * parses HTTP request headers.
- *
- * The following fields are set by this function (when successful)
- *
- * headers
- * request
- * xml_encoding
- * SOAPAction
- *
- * @access private
- */
- function parse_http_headers()
- {
- global $HTTP_SERVER_VARS;
-
- $this->request = '';
- $this->SOAPAction = '';
- if (function_exists('getallheaders')) {
- $this->debug("In parse_http_headers, use getallheaders");
- $headers = getallheaders();
- foreach ($headers as $k => $v) {
- $k = strtolower($k);
- $this->headers[$k] = $v;
- $this->request .= "$k: $v\r\n";
- $this->debug("$k: $v");
- }
- // get SOAPAction header
- if (isset($this->headers['soapaction'])) {
- $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']);
- }
- // get the character encoding of the incoming request
- if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) {
- $enc = str_replace('"', '', substr(strstr($this->headers["content-type"], '='), 1));
- if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
- $this->xml_encoding = strtoupper($enc);
- } else {
- $this->xml_encoding = 'US-ASCII';
- }
- } else {
- // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
- $this->xml_encoding = 'ISO-8859-1';
- }
- } elseif (isset($_SERVER) && is_array($_SERVER)) {
- $this->debug("In parse_http_headers, use _SERVER");
- foreach ($_SERVER as $k => $v) {
- if (substr($k, 0, 5) == 'HTTP_') {
- $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
- } else {
- $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
- }
- if ($k == 'soapaction') {
- // get SOAPAction header
- $k = 'SOAPAction';
- $v = str_replace('"', '', $v);
- $v = str_replace('\\', '', $v);
- $this->SOAPAction = $v;
- } elseif ($k == 'content-type') {
- // get the character encoding of the incoming request
- if (strpos($v, '=')) {
- $enc = substr(strstr($v, '='), 1);
- $enc = str_replace('"', '', $enc);
- $enc = str_replace('\\', '', $enc);
- if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
- $this->xml_encoding = strtoupper($enc);
- } else {
- $this->xml_encoding = 'US-ASCII';
- }
- } else {
- // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
- $this->xml_encoding = 'ISO-8859-1';
- }
- }
- $this->headers[$k] = $v;
- if (is_array($v)) {
- $this->request .= "$k: " . json_encode($v) . "\r\n";
- $this->debug("$k: " . json_encode($v));
- } else {
- $this->request .= "$k: $v\r\n";
- $this->debug("$k: $v");
- }
- }
- } elseif (is_array($HTTP_SERVER_VARS)) {
- $this->debug("In parse_http_headers, use HTTP_SERVER_VARS");
- foreach ($HTTP_SERVER_VARS as $k => $v) {
- if (substr($k, 0, 5) == 'HTTP_') {
- $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
- $k = strtolower(substr($k, 5));
- } else {
- $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
- $k = strtolower($k);
- }
- if ($k == 'soapaction') {
- // get SOAPAction header
- $k = 'SOAPAction';
- $v = str_replace('"', '', $v);
- $v = str_replace('\\', '', $v);
- $this->SOAPAction = $v;
- } elseif ($k == 'content-type') {
- // get the character encoding of the incoming request
- if (strpos($v, '=')) {
- $enc = substr(strstr($v, '='), 1);
- $enc = str_replace('"', '', $enc);
- $enc = str_replace('\\', '', $enc);
- if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
- $this->xml_encoding = strtoupper($enc);
- } else {
- $this->xml_encoding = 'US-ASCII';
- }
- } else {
- // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
- $this->xml_encoding = 'ISO-8859-1';
- }
- }
- $this->headers[$k] = $v;
- $this->request .= "$k: $v\r\n";
- $this->debug("$k: $v");
- }
- } else {
- $this->debug("In parse_http_headers, HTTP headers not accessible");
- $this->setError("HTTP headers not accessible");
- }
- }
-
- /**
- * parses a request
- *
- * The following fields are set by this function (when successful)
- *
- * headers
- * request
- * xml_encoding
- * SOAPAction
- * request
- * requestSOAP
- * methodURI
- * methodname
- * methodparams
- * requestHeaders
- * document
- *
- * This sets the fault field on error
- *
- * @param string $data XML string
- * @access private
- */
- function parse_request($data = '')
- {
- $this->debug('entering parse_request()');
- $this->parse_http_headers();
- $this->debug('got character encoding: ' . $this->xml_encoding);
- // uncompress if necessary
- if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
- $this->debug('got content encoding: ' . $this->headers['content-encoding']);
- if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') {
- // if decoding works, use it. else assume data wasn't gzencoded
- if (function_exists('gzuncompress')) {
- if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) {
- $data = $degzdata;
- } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) {
- $data = $degzdata;
- } else {
- $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
- return;
- }
- } else {
- $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
- return;
- }
- }
- }
- $this->request .= "\r\n" . $data;
- $data = $this->parseRequest($this->headers, $data);
- $this->requestSOAP = $data;
- $this->debug('leaving parse_request');
- }
-
- /**
- * invokes a PHP function for the requested SOAP method
- *
- * The following fields are set by this function (when successful)
- *
- * methodreturn
- *
- * Note that the PHP function that is called may also set the following
- * fields to affect the response sent to the client
- *
- * responseHeaders
- * outgoing_headers
- *
- * This sets the fault field on error
- *
- * @access private
- */
- function invoke_method()
- {
- $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
-
- //
- // if you are debugging in this area of the code, your service uses a class to implement methods,
- // you use SOAP RPC, and the client is .NET, please be aware of the following...
- // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
- // method name. that is fine for naming the .NET methods. it is not fine for properly constructing
- // the XML request and reading the XML response. you need to add the RequestElementName and
- // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
- // generates for the method. these parameters are used to specify the correct XML element names
- // for .NET to use, i.e. the names with the '.' in them.
- //
- $orig_methodname = $this->methodname;
- if ($this->wsdl) {
- if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
- $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
- $this->appendDebug('opData=' . $this->varDump($this->opData));
- } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
- // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
- $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
- $this->appendDebug('opData=' . $this->varDump($this->opData));
- $this->methodname = $this->opData['name'];
- } else {
- $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
- $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
- return;
- }
- } else {
- $this->debug('in invoke_method, no WSDL to validate method');
- }
-
- // if a . is present in $this->methodname, we see if there is a class in scope,
- // which could be referred to. We will also distinguish between two deliminators,
- // to allow methods to be called a the class or an instance
- if (strpos($this->methodname, '..') > 0) {
- $delim = '..';
- } elseif (strpos($this->methodname, '.') > 0) {
- $delim = '.';
- } else {
- $delim = '';
- }
- $this->debug("in invoke_method, delim=$delim");
-
- $class = '';
- $method = '';
- if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
- $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
- if (class_exists($try_class)) {
- // get the class and method name
- $class = $try_class;
- $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
- $this->debug("in invoke_method, class=$class method=$method delim=$delim");
- } else {
- $this->debug("in invoke_method, class=$try_class not found");
- }
- } elseif (strlen($delim) > 0 && substr_count($this->methodname, $delim) > 1) {
- $split = explode($delim, $this->methodname);
- $method = array_pop($split);
- $class = implode('\\', $split);
- } else {
- $try_class = '';
- $this->debug("in invoke_method, no class to try");
- }
-
- // does method exist?
- if ($class == '') {
- if (!function_exists($this->methodname)) {
- $this->debug("in invoke_method, function '$this->methodname' not found!");
- $this->result = 'fault: method not found';
- $this->fault('SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
- return;
- }
- } else {
- $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method;
- if (!in_array($method_to_compare, get_class_methods($class))) {
- $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
- $this->result = 'fault: method not found';
- $this->fault('SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
- return;
- }
- }
-
- // evaluate message, getting back parameters
- // verify that request parameters match the method's signature
- if (!$this->verify_method($this->methodname, $this->methodparams)) {
- // debug
- $this->debug('ERROR: request not verified against method signature');
- $this->result = 'fault: request failed validation against method signature';
- // return fault
- $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service.");
- return;
- }
-
- // if there are parameters to pass
- $this->debug('in invoke_method, params:');
- $this->appendDebug($this->varDump($this->methodparams));
- $this->debug("in invoke_method, calling '$this->methodname'");
- if (!function_exists('call_user_func_array')) {
- if ($class == '') {
- $this->debug('in invoke_method, calling function using eval()');
- $funcCall = "\$this->methodreturn = $this->methodname(";
- } else {
- if ($delim == '..') {
- $this->debug('in invoke_method, calling class method using eval()');
- $funcCall = "\$this->methodreturn = " . $class . "::" . $method . "(";
- } else {
- $this->debug('in invoke_method, calling instance method using eval()');
- // generate unique instance name
- $instname = "\$inst_" . time();
- $funcCall = $instname . " = new " . $class . "(); ";
- $funcCall .= "\$this->methodreturn = " . $instname . "->" . $method . "(";
- }
- }
- if ($this->methodparams) {
- foreach ($this->methodparams as $param) {
- if (is_array($param) || is_object($param)) {
- $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
- return;
- }
- $funcCall .= "\"$param\",";
- }
- $funcCall = substr($funcCall, 0, -1);
- }
- $funcCall .= ');';
- $this->debug('in invoke_method, function call: ' . $funcCall);
- @eval($funcCall);
- } else {
- if ($class == '') {
- $this->debug('in invoke_method, calling function using call_user_func_array()');
- $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array()
- } elseif ($delim == '..') {
- $this->debug('in invoke_method, calling class method using call_user_func_array()');
- $call_arg = array($class, $method);
- } else {
- $this->debug('in invoke_method, calling instance method using call_user_func_array()');
- $instance = new $class ();
- $call_arg = array(&$instance, $method);
- }
- if (is_array($this->methodparams)) {
- $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
- } else {
- $this->methodreturn = call_user_func_array($call_arg, array());
- }
- }
- $this->debug('in invoke_method, methodreturn:');
- $this->appendDebug($this->varDump($this->methodreturn));
- $this->debug("in invoke_method, called method $this->methodname, received data of type " . gettype($this->methodreturn));
- }
-
- /**
- * serializes the return value from a PHP function into a full SOAP Envelope
- *
- * The following fields are set by this function (when successful)
- *
- * responseSOAP
- *
- * This sets the fault field on error
- *
- * @access private
- */
- function serialize_return()
- {
- $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
- // if fault
- if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) {
- $this->debug('got a fault object from method');
- $this->fault = $this->methodreturn;
- return;
- } elseif ($this->methodreturnisliteralxml) {
- $return_val = $this->methodreturn;
- // returned value(s)
- } else {
- $this->debug('got a(n) ' . gettype($this->methodreturn) . ' from method');
- $this->debug('serializing return value');
- if ($this->wsdl) {
- if (sizeof($this->opData['output']['parts']) > 1) {
- $this->debug('more than one output part, so use the method return unchanged');
- $opParams = $this->methodreturn;
- } elseif (sizeof($this->opData['output']['parts']) == 1) {
- $this->debug('exactly one output part, so wrap the method return in a simple array');
- // TODO: verify that it is not already wrapped!
- //foreach ($this->opData['output']['parts'] as $name => $type) {
- // $this->debug('wrap in element named ' . $name);
- //}
- $opParams = array($this->methodreturn);
- }
- $opParams = isset($opParams) ? $opParams : [];
- $return_val = $this->wsdl->serializeRPCParameters($this->methodname, 'output', $opParams);
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- if ($errstr = $this->wsdl->getError()) {
- $this->debug('got wsdl error: ' . $errstr);
- $this->fault('SOAP-ENV:Server', 'unable to serialize result');
- return;
- }
- } else {
- if (isset($this->methodreturn)) {
- $return_val = $this->serialize_val($this->methodreturn, 'return');
- } else {
- $return_val = '';
- $this->debug('in absence of WSDL, assume void return for backward compatibility');
- }
- }
- }
- $this->debug('return value:');
- $this->appendDebug($this->varDump($return_val));
-
- $this->debug('serializing response');
- if ($this->wsdl) {
- $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
- if ($this->opData['style'] == 'rpc') {
- $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
- if ($this->opData['output']['use'] == 'literal') {
- // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
- if ($this->methodURI) {
- $payload = 'methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . ' methodname . "Response>";
- } else {
- $payload = '<' . $this->methodname . 'Response>' . $return_val . '' . $this->methodname . 'Response>';
- }
- } else {
- if ($this->methodURI) {
- $payload = 'methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . ' methodname . "Response>";
- } else {
- $payload = '<' . $this->methodname . 'Response>' . $return_val . '' . $this->methodname . 'Response>';
- }
- }
- } else {
- $this->debug('style is not rpc for serialization: assume document');
- $payload = $return_val;
- }
- } else {
- $this->debug('do not have WSDL for serialization: assume rpc/encoded');
- $payload = 'methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . ' methodname . "Response>";
- }
- $this->result = 'successful';
- if ($this->wsdl) {
- //if($this->debug_flag){
- $this->appendDebug($this->wsdl->getDebug());
- // }
- if (isset($this->opData['output']['encodingStyle'])) {
- $encodingStyle = $this->opData['output']['encodingStyle'];
- } else {
- $encodingStyle = '';
- }
- // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
- $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle);
- } else {
- $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders);
- }
- $this->debug("Leaving serialize_return");
- }
-
- /**
- * sends an HTTP response
- *
- * The following fields are set by this function (when successful)
- *
- * outgoing_headers
- * response
- *
- * @access private
- */
- function send_response()
- {
- $this->debug('Enter send_response');
- if ($this->fault) {
- $payload = $this->fault->serialize();
- $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error";
- $this->outgoing_headers[] = "Status: 500 Internal Server Error";
- } else {
- $payload = $this->responseSOAP;
- // Some combinations of PHP+Web server allow the Status
- // to come through as a header. Since OK is the default
- // just do nothing.
- // $this->outgoing_headers[] = "HTTP/1.0 200 OK";
- // $this->outgoing_headers[] = "Status: 200 OK";
- }
- // add debug data if in debug mode
- if (isset($this->debug_flag) && $this->debug_flag) {
- $payload .= $this->getDebugAsXMLComment();
- }
- $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
- preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
- $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ")";
- // Let the Web server decide about this
- //$this->outgoing_headers[] = "Connection: Close\r\n";
- $payload = $this->getHTTPBody($payload);
- $type = $this->getHTTPContentType();
- $charset = $this->getHTTPContentTypeCharset();
- $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
- //begin code to compress payload - by John
- // NOTE: there is no way to know whether the Web server will also compress
- // this data.
- if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
- if (strstr($this->headers['accept-encoding'], 'gzip')) {
- if (function_exists('gzencode')) {
- if (isset($this->debug_flag) && $this->debug_flag) {
- $payload .= "";
- }
- $this->outgoing_headers[] = "Content-Encoding: gzip";
- $payload = gzencode($payload);
- } else {
- if (isset($this->debug_flag) && $this->debug_flag) {
- $payload .= "";
- }
- }
- } elseif (strstr($this->headers['accept-encoding'], 'deflate')) {
- // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
- // instead of gzcompress output,
- // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
- if (function_exists('gzdeflate')) {
- if (isset($this->debug_flag) && $this->debug_flag) {
- $payload .= "";
- }
- $this->outgoing_headers[] = "Content-Encoding: deflate";
- $payload = gzdeflate($payload);
- } else {
- if (isset($this->debug_flag) && $this->debug_flag) {
- $payload .= "";
- }
- }
- }
- }
- //end code
- $this->outgoing_headers[] = "Content-Length: " . strlen($payload);
- reset($this->outgoing_headers);
- foreach ($this->outgoing_headers as $hdr) {
- header($hdr, false);
- }
- print $payload;
- $this->response = join("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload;
- }
-
- /**
- * takes the value that was created by parsing the request
- * and compares to the method's signature, if available.
- *
- * @param string $operation The operation to be invoked
- * @param array $request The array of parameter values
- * @return boolean Whether the operation was found
- * @access private
- */
- function verify_method($operation, $request)
- {
- if (isset($this->wsdl) && is_object($this->wsdl)) {
- if ($this->wsdl->getOperationData($operation)) {
- return true;
- }
- } elseif (isset($this->operations[$operation])) {
- return true;
- }
- return false;
- }
-
- /**
- * processes SOAP message received from client
- *
- * @param array $headers The HTTP headers
- * @param string $data unprocessed request data from client
- * @return mixed value of the message, decoded into a PHP type
- * @access private
- */
- function parseRequest($headers, $data)
- {
- $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
- $this->appendDebug($this->varDump($headers));
- if (!isset($headers['content-type'])) {
- $this->setError('Request not of type '.$this->contentType.' (no content-type header)');
- return false;
- }
- if (!strstr($headers['content-type'], $this->contentType)) {
- $this->setError('Request not of type '.$this->contentType.': ' . $headers['content-type']);
- return false;
- }
- if (strpos($headers['content-type'], '=')) {
- $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
- $this->debug('Got response encoding: ' . $enc);
- if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
- $this->xml_encoding = strtoupper($enc);
- } else {
- $this->xml_encoding = 'US-ASCII';
- }
- } else {
- // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
- $this->xml_encoding = 'ISO-8859-1';
- }
- $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
- // parse response, get soap parser obj
- $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8);
- // parser debug
- $this->debug("parser debug: \n" . $parser->getDebug());
- // if fault occurred during message parsing
- if ($err = $parser->getError()) {
- $this->result = 'fault: error in msg parsing: ' . $err;
- $this->fault('SOAP-ENV:Client', "error in msg parsing:\n" . $err);
- // else successfully parsed request into soapval object
- } else {
- // get/set methodname
- $this->methodURI = $parser->root_struct_namespace;
- $this->methodname = $parser->root_struct_name;
- $this->debug('methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
- $this->debug('calling parser->get_soapbody()');
- $this->methodparams = $parser->get_soapbody();
- // get SOAP headers
- $this->requestHeaders = $parser->getHeaders();
- // get SOAP Header
- $this->requestHeader = $parser->get_soapheader();
- // add document for doclit support
- $this->document = $parser->document;
- }
- }
-
- /**
- * gets the HTTP body for the current response.
- *
- * @param string $soapmsg The SOAP payload
- * @return string The HTTP body, which includes the SOAP payload
- * @access private
- */
- function getHTTPBody($soapmsg)
- {
- return $soapmsg;
- }
-
- /**
- * gets the HTTP content type for the current response.
- *
- * Note: getHTTPBody must be called before this.
- *
- * @return string the HTTP content type for the current response.
- * @access private
- */
- function getHTTPContentType()
- {
- return 'text/xml';
- }
-
- /**
- * gets the HTTP content type charset for the current response.
- * returns false for non-text content types.
- *
- * Note: getHTTPBody must be called before this.
- *
- * @return string the HTTP content type charset for the current response.
- * @access private
- */
- function getHTTPContentTypeCharset()
- {
- return $this->soap_defencoding;
- }
-
- /**
- * add a method to the dispatch map (this has been replaced by the register method)
- *
- * @param string $methodname
- * @param string $in array of input values
- * @param string $out array of output values
- * @access public
- * @deprecated
- */
- function add_to_map($methodname, $in, $out)
- {
- $this->operations[$methodname] = array('name' => $methodname, 'in' => $in, 'out' => $out);
- }
-
- /**
- * register a service function with the server
- *
- * @param string $name the name of the PHP function, class.method or class..method
- * @param array $in assoc array of input values: key = param name, value = param type
- * @param array $out assoc array of output values: key = param name, value = param type
- * @param mixed $namespace the element namespace for the method or false
- * @param mixed $soapaction the soapaction for the method or false
- * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
- * @param mixed $use optional (encoded|literal) or false
- * @param string $documentation optional Description to include in WSDL
- * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
- * @access public
- */
- function register($name, $in = array(), $out = array(), $namespace = false, $soapaction = false, $style = false, $use = false, $documentation = '', $encodingStyle = '')
- {
- global $HTTP_SERVER_VARS;
-
- if ($this->externalWSDLURL) {
- die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.');
- }
- if (!$name) {
- die('You must specify a name when you register an operation');
- }
- if (!is_array($in)) {
- die('You must provide an array for operation inputs');
- }
- if (!is_array($out)) {
- die('You must provide an array for operation outputs');
- }
- if (false == $namespace) {
- }
- if (false == $soapaction) {
- if (isset($_SERVER)) {
- $SERVER_NAME = $_SERVER['SERVER_NAME'];
- $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
- $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
- } elseif (isset($HTTP_SERVER_VARS)) {
- $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
- $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
- $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
- } else {
- $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
- }
- if ($HTTPS == '1' || $HTTPS == 'on') {
- $SCHEME = 'https';
- } else {
- $SCHEME = 'http';
- }
- $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name";
- }
- if (false == $style) {
- $style = "rpc";
- }
- if (false == $use) {
- $use = "encoded";
- }
- if ($use == 'encoded' && $encodingStyle == '') {
- $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
- }
-
- $this->operations[$name] = array(
- 'name' => $name,
- 'in' => $in,
- 'out' => $out,
- 'namespace' => $namespace,
- 'soapaction' => $soapaction,
- 'style' => $style);
- if ($this->wsdl) {
- $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle);
- }
- return true;
- }
-
- /**
- * Specify a fault to be returned to the client.
- * This also acts as a flag to the server that a fault has occured.
- *
- * @param string $faultcode
- * @param string $faultstring
- * @param string $faultactor
- * @param string $faultdetail
- * @access public
- */
- function fault($faultcode, $faultstring, $faultactor = '', $faultdetail = '')
- {
- if ($faultdetail == '' && $this->debug_flag) {
- $faultdetail = $this->getDebug();
- }
- $this->fault = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail);
- $this->fault->soap_defencoding = $this->soap_defencoding;
- }
-
- /**
- * Sets up wsdl object.
- * Acts as a flag to enable internal WSDL generation
- *
- * @param string $serviceName , name of the service
- * @param mixed $namespace optional 'tns' service namespace or false
- * @param mixed $endpoint optional URL of service endpoint or false
- * @param string $style optional (rpc|document) WSDL style (also specified by operation)
- * @param string $transport optional SOAP transport
- * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
- */
- function configureWSDL($serviceName, $namespace = false, $endpoint = false, $style = 'rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false)
- {
- global $HTTP_SERVER_VARS;
-
- if (isset($_SERVER)) {
- $SERVER_NAME = $_SERVER['SERVER_NAME'];
- $SERVER_PORT = $_SERVER['SERVER_PORT'];
- $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
- $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
- } elseif (isset($HTTP_SERVER_VARS)) {
- $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
- $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
- $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
- $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
- } else {
- $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
- }
- // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
- $colon = strpos($SERVER_NAME, ":");
- if ($colon) {
- $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
- }
- if ($SERVER_PORT == 80) {
- $SERVER_PORT = '';
- } else {
- $SERVER_PORT = ':' . $SERVER_PORT;
- }
- if (false == $namespace) {
- $namespace = "http://$SERVER_NAME/soap/$serviceName";
- }
-
- if (false == $endpoint) {
- if ($HTTPS == '1' || $HTTPS == 'on') {
- $SCHEME = 'https';
- } else {
- $SCHEME = 'http';
- }
- $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME";
- }
-
- if (false == $schemaTargetNamespace) {
- $schemaTargetNamespace = $namespace;
- }
-
- $this->wsdl = new wsdl;
- $this->wsdl->serviceName = $serviceName;
- $this->wsdl->endpoint = $endpoint;
- $this->wsdl->namespaces['tns'] = $namespace;
- $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
- $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
- if ($schemaTargetNamespace != $namespace) {
- $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
- }
- $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
- if ($style == 'document') {
- $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
- }
- $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace;
- $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true);
- $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true);
- $this->wsdl->bindings[$serviceName . 'Binding'] = array(
- 'name' => $serviceName . 'Binding',
- 'style' => $style,
- 'transport' => $transport,
- 'portType' => $serviceName . 'PortType');
- $this->wsdl->ports[$serviceName . 'Port'] = array(
- 'binding' => $serviceName . 'Binding',
- 'location' => $endpoint,
- 'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/');
- }
-}
-
-/**
- * Backward compatibility
- */
-class soap_server extends nusoap_server
-{
-}
-
-
-/**
- * parses a WSDL file, allows access to it's data, other utility methods.
- * also builds WSDL structures programmatically.
- *
- * @author Dietrich Ayala
- * @author Scott Nichol
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class wsdl extends nusoap_base
-{
- // URL or filename of the root of this WSDL
- var $wsdl;
- // define internal arrays of bindings, ports, operations, messages, etc.
- var $schemas = array();
- var $currentSchema;
- var $message = array();
- var $complexTypes = array();
- var $messages = array();
- var $currentMessage;
- var $currentOperation;
- var $portTypes = array();
- var $currentPortType;
- var $bindings = array();
- var $currentBinding;
- var $ports = array();
- var $currentPort;
- var $opData = array();
- var $status = '';
- var $documentation = false;
- var $endpoint = '';
- // array of wsdl docs to import
- var $import = array();
- // parser vars
- var $parser;
- var $position = 0;
- var $depth = 0;
- var $depth_array = array();
- // for getting wsdl
- var $proxyhost = '';
- var $proxyport = '';
- var $proxyusername = '';
- var $proxypassword = '';
- var $timeout = 0;
- var $response_timeout = 30;
- var $curl_options = array(); // User-specified cURL options
- var $use_curl = false; // whether to always try to use cURL
- // for HTTP authentication
- var $username = ''; // Username for HTTP authentication
- var $password = ''; // Password for HTTP authentication
- var $authtype = ''; // Type of HTTP authentication
- var $certRequest = array(); // Certificate for HTTP SSL authentication
-
- /**
- * constructor
- *
- * @param string $wsdl WSDL document URL
- * @param string $proxyhost
- * @param string $proxyport
- * @param string $proxyusername
- * @param string $proxypassword
- * @param integer $timeout set the connection timeout
- * @param integer $response_timeout set the response timeout
- * @param array $curl_options user-specified cURL options
- * @param boolean $use_curl try to use cURL
- * @access public
- */
- function __construct($wsdl = '', $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $curl_options = null, $use_curl = false)
- {
- parent::__construct();
- $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
- $this->proxyhost = $proxyhost;
- $this->proxyport = $proxyport;
- $this->proxyusername = $proxyusername;
- $this->proxypassword = $proxypassword;
- $this->timeout = $timeout;
- $this->response_timeout = $response_timeout;
- if (is_array($curl_options)) {
- $this->curl_options = $curl_options;
- }
- $this->use_curl = $use_curl;
- $this->fetchWSDL($wsdl);
- }
-
- /**
- * fetches the WSDL document and parses it
- *
- * @access public
- */
- function fetchWSDL($wsdl)
- {
- $this->debug("parse and process WSDL path=$wsdl");
- $this->wsdl = $wsdl;
- // parse wsdl file
- if ($this->wsdl != "") {
- $this->parseWSDL($this->wsdl);
- }
- // imports
- // TODO: handle imports more properly, grabbing them in-line and nesting them
- $imported_urls = array();
- $imported = 1;
- while ($imported > 0) {
- $imported = 0;
- // Schema imports
- foreach ($this->schemas as $ns => $list) {
- foreach ($list as $xs) {
- $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
- foreach ($xs->imports as $ns2 => $list2) {
- for ($ii = 0; $ii < count($list2); $ii++) {
- if (array_key_exists($ii, $list2) && !isset($list2[$ii]['loaded'])) {
- $this->schemas[$ns][$ns2]->imports[$ns2][$ii]['loaded'] = true;
- $url = $list2[$ii]['location'];
- if ($url != '') {
- $urlparts = parse_url($url);
- if (!isset($urlparts['host'])) {
- $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
- substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
- }
- if (!in_array($url, $imported_urls)) {
- $this->parseWSDL($url);
- $imported++;
- $imported_urls[] = $url;
- }
- } else {
- $this->debug("Unexpected scenario: empty URL for unloaded import");
- }
- }
- }
- }
- }
- }
- // WSDL imports
- $wsdlparts = parse_url($this->wsdl); // this is bogusly simple!
- foreach ($this->import as $ns => $list) {
- for ($ii = 0; $ii < count($list); $ii++) {
- if (!$list[$ii]['loaded']) {
- $this->import[$ns][$ii]['loaded'] = true;
- $url = $list[$ii]['location'];
- if ($url != '') {
- $urlparts = parse_url($url);
- if (!isset($urlparts['host'])) {
- $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') .
- substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
- }
- if (!in_array($url, $imported_urls)) {
- $this->parseWSDL($url);
- $imported++;
- $imported_urls[] = $url;
- }
- } else {
- $this->debug("Unexpected scenario: empty URL for unloaded import");
- }
- }
- }
- }
- }
- // add new data to operation data
- foreach ($this->bindings as $binding => $bindingData) {
- if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
- foreach ($bindingData['operations'] as $operation => $data) {
- $this->debug('post-parse data gathering for ' . $operation);
- $this->bindings[$binding]['operations'][$operation]['input'] =
- isset($this->bindings[$binding]['operations'][$operation]['input']) ?
- array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[$bindingData['portType']][$operation]['input']) :
- $this->portTypes[$bindingData['portType']][$operation]['input'];
- $this->bindings[$binding]['operations'][$operation]['output'] =
- isset($this->bindings[$binding]['operations'][$operation]['output']) ?
- array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[$bindingData['portType']][$operation]['output']) :
- $this->portTypes[$bindingData['portType']][$operation]['output'];
- if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']])) {
- $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']];
- }
- if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']])) {
- $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']];
- }
- // Set operation style if necessary, but do not override one already provided
- if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) {
- $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
- }
- $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : '';
- $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[$bindingData['portType']][$operation]['documentation']) ? $this->portTypes[$bindingData['portType']][$operation]['documentation'] : '';
- $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
- }
- }
- }
- }
-
- /**
- * parses the wsdl document
- *
- * @param string $wsdl path or URL
- * @access private
- */
- function parseWSDL($wsdl = '')
- {
- $this->debug("parse WSDL at path=$wsdl");
-
- if ($wsdl == '') {
- $this->debug('no wsdl passed to parseWSDL()!!');
- $this->setError('no wsdl passed to parseWSDL()!!');
- return false;
- }
-
- // parse $wsdl for url format
- $wsdl_props = parse_url($wsdl);
-
- if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) {
- $this->debug('getting WSDL http(s) URL ' . $wsdl);
- // get wsdl
- $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
- $tr->request_method = 'GET';
- $tr->useSOAPAction = false;
- if ($this->proxyhost && $this->proxyport) {
- $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
- }
- if ($this->authtype != '') {
- $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
- }
- $tr->setEncoding('gzip, deflate');
- $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
- //$this->debug("WSDL request\n" . $tr->outgoing_payload);
- //$this->debug("WSDL response\n" . $tr->incoming_payload);
- $this->appendDebug($tr->getDebug());
- // catch errors
- if ($err = $tr->getError()) {
- $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: ' . $err;
- $this->debug($errstr);
- $this->setError($errstr);
- unset($tr);
- return false;
- }
- unset($tr);
- $this->debug("got WSDL URL");
- } else {
- // $wsdl is not http(s), so treat it as a file URL or plain file path
- if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) {
- $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
- } else {
- $path = $wsdl;
- }
- $this->debug('getting WSDL file ' . $path);
- if ($fp = @fopen($path, 'r')) {
- $wsdl_string = '';
- while ($data = fread($fp, 32768)) {
- $wsdl_string .= $data;
- }
- fclose($fp);
- } else {
- $errstr = "Bad path to WSDL file $path";
- $this->debug($errstr);
- $this->setError($errstr);
- return false;
- }
- }
- $this->debug('Parse WSDL');
- // end new code added
- // Create an XML parser.
- $this->parser = xml_parser_create();
- // Set the options for parsing the XML data.
- // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
- xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
- // Set the object for the parser.
- xml_set_object($this->parser, $this);
- // Set the element handlers for the parser.
- xml_set_element_handler($this->parser, 'start_element', 'end_element');
- xml_set_character_data_handler($this->parser, 'character_data');
- // Parse the XML file.
- if (!xml_parse($this->parser, $wsdl_string, true)) {
- // Display an error message.
- $errstr = sprintf(
- 'XML error parsing WSDL from %s on line %d: %s',
- $wsdl,
- xml_get_current_line_number($this->parser),
- xml_error_string(xml_get_error_code($this->parser))
- );
- $this->debug($errstr);
- $this->debug("XML payload:\n" . $wsdl_string);
- $this->setError($errstr);
- xml_parser_free($this->parser);
- unset($this->parser);
- return false;
- }
- // free the parser
- xml_parser_free($this->parser);
- unset($this->parser);
- $this->debug('Parsing WSDL done');
- // catch wsdl parse errors
- if ($this->getError()) {
- return false;
- }
- return true;
- }
-
- /**
- * start-element handler
- *
- * @param string $parser XML parser object
- * @param string $name element name
- * @param string $attrs associative array of attributes
- * @access private
- */
- function start_element($parser, $name, $attrs)
- {
- if ($this->status == 'schema') {
- $this->currentSchema->schemaStartElement($parser, $name, $attrs);
- $this->appendDebug($this->currentSchema->getDebug());
- $this->currentSchema->clearDebug();
- } elseif (preg_match('/schema$/', $name)) {
- $this->debug('Parsing WSDL schema');
- // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")");
- $this->status = 'schema';
- $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
- $this->currentSchema->schemaStartElement($parser, $name, $attrs);
- $this->appendDebug($this->currentSchema->getDebug());
- $this->currentSchema->clearDebug();
- } else {
- // position in the total number of elements, starting from 0
- $pos = $this->position++;
- $depth = $this->depth++;
- // set self as current value for this depth
- $this->depth_array[$depth] = $pos;
- $this->message[$pos] = array('cdata' => '');
- // process attributes
- if (count($attrs) > 0) {
- // register namespace declarations
- foreach ($attrs as $k => $v) {
- if (preg_match('/^xmlns/', $k)) {
- if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
- $this->namespaces[$ns_prefix] = $v;
- } else {
- $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
- }
- if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') {
- $this->XMLSchemaVersion = $v;
- $this->namespaces['xsi'] = $v . '-instance';
- }
- }
- }
- // expand each attribute prefix to its namespace
- foreach ($attrs as $k => $v) {
- $k = strpos($k, ':') ? $this->expandQname($k) : $k;
- if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') {
- $v = strpos($v, ':') ? $this->expandQname($v) : $v;
- }
- $eAttrs[$k] = $v;
- }
- $attrs = $eAttrs;
- } else {
- $attrs = array();
- }
- // Set default prefix and namespace
- // to prevent error Undefined variable $prefix and $namespace if (preg_match('/:/', $name)) return 0 or FALSE
- $prefix = '';
- $namespace = '';
- // get element prefix, namespace and name
- if (preg_match('/:/', $name)) {
- // get ns prefix
- $prefix = substr($name, 0, strpos($name, ':'));
- // get ns
- $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
- // get unqualified name
- $name = substr(strstr($name, ':'), 1);
- }
- // process attributes, expanding any prefixes to namespaces
- // find status, register data
- switch ($this->status) {
- case 'message':
- if ($name == 'part') {
- if (isset($attrs['type'])) {
- $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
- $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
- }
- if (isset($attrs['element'])) {
- $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
- $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
- }
- }
- break;
- case 'portType':
- switch ($name) {
- case 'operation':
- $this->currentPortOperation = $attrs['name'];
- $this->debug("portType $this->currentPortType operation: $this->currentPortOperation");
- if (isset($attrs['parameterOrder'])) {
- $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
- }
- break;
- case 'documentation':
- $this->documentation = true;
- break;
- // merge input/output data
- default:
- $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
- $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m;
- break;
- }
- break;
- case 'binding':
- switch ($name) {
- case 'binding':
- // get ns prefix
- if (isset($attrs['style'])) {
- $this->bindings[$this->currentBinding]['prefix'] = $prefix;
- }
- $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
- break;
- case 'header':
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs;
- break;
- case 'operation':
- if (isset($attrs['soapAction'])) {
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
- }
- if (isset($attrs['style'])) {
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
- }
- if (isset($attrs['name'])) {
- $this->currentOperation = $attrs['name'];
- $this->debug("current binding operation: $this->currentOperation");
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name'];
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding;
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
- }
- break;
- case 'input':
- $this->opStatus = 'input';
- break;
- case 'output':
- $this->opStatus = 'output';
- break;
- case 'body':
- if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) {
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs);
- } else {
- $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs;
- }
- break;
- }
- break;
- case 'service':
- switch ($name) {
- case 'port':
- $this->currentPort = $attrs['name'];
- $this->debug('current port: ' . $this->currentPort);
- $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
-
- break;
- case 'address':
- $this->ports[$this->currentPort]['location'] = $attrs['location'];
- $this->ports[$this->currentPort]['bindingType'] = $namespace;
- $this->bindings[$this->ports[$this->currentPort]['binding']]['bindingType'] = $namespace;
- $this->bindings[$this->ports[$this->currentPort]['binding']]['endpoint'] = $attrs['location'];
- break;
- }
- break;
- }
- // set status
- switch ($name) {
- case 'import':
- if (isset($attrs['location'])) {
- $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false);
- $this->debug('parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]) . ')');
- } else {
- $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
- if (!$this->getPrefixFromNamespace($attrs['namespace'])) {
- $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
- }
- $this->debug('parsing import ' . $attrs['namespace'] . ' - [no location] (' . count($this->import[$attrs['namespace']]) . ')');
- }
- break;
- //wait for schema
- //case 'types':
- // $this->status = 'schema';
- // break;
- case 'message':
- $this->status = 'message';
- $this->messages[$attrs['name']] = array();
- $this->currentMessage = $attrs['name'];
- break;
- case 'portType':
- $this->status = 'portType';
- $this->portTypes[$attrs['name']] = array();
- $this->currentPortType = $attrs['name'];
- break;
- case "binding":
- if (isset($attrs['name'])) {
- // get binding name
- if (strpos($attrs['name'], ':')) {
- $this->currentBinding = $this->getLocalPart($attrs['name']);
- } else {
- $this->currentBinding = $attrs['name'];
- }
- $this->status = 'binding';
- $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
- $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
- }
- break;
- case 'service':
- $this->serviceName = $attrs['name'];
- $this->status = 'service';
- $this->debug('current service: ' . $this->serviceName);
- break;
- case 'definitions':
- foreach ($attrs as $name => $value) {
- $this->wsdl_info[$name] = $value;
- }
- break;
- }
- }
- }
-
- /**
- * end-element handler
- *
- * @param string $parser XML parser object
- * @param string $name element name
- * @access private
- */
- function end_element($parser, $name)
- {
- // unset schema status
- if (/*preg_match('/types$/', $name) ||*/
- preg_match('/schema$/', $name)
- ) {
- $this->status = "";
- $this->appendDebug($this->currentSchema->getDebug());
- $this->currentSchema->clearDebug();
- $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
- $this->debug('Parsing WSDL schema done');
- }
- if ($this->status == 'schema') {
- $this->currentSchema->schemaEndElement($parser, $name);
- } else {
- // bring depth down a notch
- $this->depth--;
- }
- // end documentation
- if ($this->documentation) {
- //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
- //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation;
- $this->documentation = false;
- }
- }
-
- /**
- * element content handler
- *
- * @param string $parser XML parser object
- * @param string $data element content
- * @access private
- */
- function character_data($parser, $data)
- {
- $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
- if (isset($this->message[$pos]['cdata'])) {
- $this->message[$pos]['cdata'] .= $data;
- }
- if ($this->documentation) {
- $this->documentation .= $data;
- }
- }
-
- /**
- * if authenticating, set user credentials here
- *
- * @param string $username
- * @param string $password
- * @param string $authtype (basic|digest|certificate|ntlm)
- * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
- * @access public
- */
- function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
- {
- $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
- $this->appendDebug($this->varDump($certRequest));
- $this->username = $username;
- $this->password = $password;
- $this->authtype = $authtype;
- $this->certRequest = $certRequest;
- }
-
- function getBindingData($binding)
- {
- if (is_array($this->bindings[$binding])) {
- return $this->bindings[$binding];
- }
- }
-
- /**
- * returns an assoc array of operation names => operation data
- *
- * @param string $portName WSDL port name
- * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
- * @return array
- * @access public
- */
- function getOperations($portName = '', $bindingType = 'soap')
- {
- $ops = array();
- if ($bindingType == 'soap') {
- $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
- } elseif ($bindingType == 'soap12') {
- $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
- } else {
- $this->debug("getOperations bindingType $bindingType may not be supported");
- }
- $this->debug("getOperations for port '$portName' bindingType $bindingType");
- // loop thru ports
- foreach ($this->ports as $port => $portData) {
- $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
- if ($portName == '' || $port == $portName) {
- // binding type of port matches parameter
- if ($portData['bindingType'] == $bindingType) {
- $this->debug("getOperations found port $port bindingType $bindingType");
- //$this->debug("port data: " . $this->varDump($portData));
- //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ]));
- // merge bindings
- if (isset($this->bindings[$portData['binding']]['operations'])) {
- $ops = array_merge($ops, $this->bindings[$portData['binding']]['operations']);
- }
- }
- }
- }
- if (count($ops) == 0) {
- $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
- }
- return $ops;
- }
-
- /**
- * returns an associative array of data necessary for calling an operation
- *
- * @param string $operation name of operation
- * @param string $bindingType type of binding eg: soap, soap12
- * @return array
- * @access public
- */
- function getOperationData($operation, $bindingType = 'soap')
- {
- if ($bindingType == 'soap') {
- $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
- } elseif ($bindingType == 'soap12') {
- $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
- }
- // loop thru ports
- foreach ($this->ports as $port => $portData) {
- // binding type of port matches parameter
- if ($portData['bindingType'] == $bindingType) {
- // get binding
- //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) {
- foreach (array_keys($this->bindings[$portData['binding']]['operations']) as $bOperation) {
- // note that we could/should also check the namespace here
- if ($operation == $bOperation) {
- $opData = $this->bindings[$portData['binding']]['operations'][$operation];
- return $opData;
- }
- }
- }
- }
- }
-
- /**
- * returns an associative array of data necessary for calling an operation
- *
- * @param string $soapAction soapAction for operation
- * @param string $bindingType type of binding eg: soap, soap12
- * @return array
- * @access public
- */
- function getOperationDataForSoapAction($soapAction, $bindingType = 'soap')
- {
- if ($bindingType == 'soap') {
- $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
- } elseif ($bindingType == 'soap12') {
- $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
- }
- // loop thru ports
- foreach ($this->ports as $port => $portData) {
- // binding type of port matches parameter
- if ($portData['bindingType'] == $bindingType) {
- // loop through operations for the binding
- foreach ($this->bindings[$portData['binding']]['operations'] as $bOperation => $opData) {
- if ($opData['soapAction'] == $soapAction) {
- return $opData;
- }
- }
- }
- }
- }
-
- /**
- * returns an array of information about a given type
- * returns false if no type exists by the given name
- *
- * typeDef = array(
- * 'elements' => array(), // refs to elements array
- * 'restrictionBase' => '',
- * 'phpType' => '',
- * 'order' => '(sequence|all)',
- * 'attrs' => array() // refs to attributes array
- * )
- *
- * @param string $type the type
- * @param string $ns namespace (not prefix) of the type
- * @return mixed
- * @access public
- * @see nusoap_xmlschema
- */
- function getTypeDef($type, $ns)
- {
- $this->debug("in getTypeDef: type=$type, ns=$ns");
- if ((!$ns) && isset($this->namespaces['tns'])) {
- $ns = $this->namespaces['tns'];
- $this->debug("in getTypeDef: type namespace forced to $ns");
- }
- if (!isset($this->schemas[$ns])) {
- foreach ($this->schemas as $ns0 => $schema0) {
- if (strcasecmp($ns, $ns0) == 0) {
- $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
- $ns = $ns0;
- break;
- }
- }
- }
- if (isset($this->schemas[$ns])) {
- $this->debug("in getTypeDef: have schema for namespace $ns");
- for ($i = 0; $i < count($this->schemas[$ns]); $i++) {
- $xs = &$this->schemas[$ns][$i];
- $t = $xs->getTypeDef($type);
- $this->appendDebug($xs->getDebug());
- $xs->clearDebug();
- if ($t) {
- $this->debug("in getTypeDef: found type $type");
- if (!isset($t['phpType'])) {
- // get info for type to tack onto the element
- $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
- $ns = substr($t['type'], 0, strrpos($t['type'], ':'));
- $etype = $this->getTypeDef($uqType, $ns);
- if ($etype) {
- $this->debug("found type for [element] $type:");
- $this->debug($this->varDump($etype));
- if (isset($etype['phpType'])) {
- $t['phpType'] = $etype['phpType'];
- }
- if (isset($etype['elements'])) {
- $t['elements'] = $etype['elements'];
- }
- if (isset($etype['attrs'])) {
- $t['attrs'] = $etype['attrs'];
- }
- } else {
- $this->debug("did not find type for [element] $type");
- }
- }
- return $t;
- }
- }
- $this->debug("in getTypeDef: did not find type $type");
- } else {
- $this->debug("in getTypeDef: do not have schema for namespace $ns");
- }
- return false;
- }
-
- /**
- * prints html description of services
- *
- * @access private
- */
- function webDescription()
- {
- global $HTTP_SERVER_VARS;
-
- if (isset($_SERVER)) {
- $PHP_SELF = $_SERVER['PHP_SELF'];
- } elseif (isset($HTTP_SERVER_VARS)) {
- $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
- } else {
- $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available");
- }
-
- $b = '
- NuSOAP: ' . $this->serviceName . '
-
-
-
-
-
-
-
' . $this->serviceName . '
-
-
View the WSDL for the service.
- Click on an operation name to view it's details.
-
';
- foreach ($this->getOperations() as $op => $data) {
- $b .= "$op ";
- // create hidden div
- $b .= "
-
Close ";
- foreach ($data as $donnie => $marie) { // loop through opdata
- if ($donnie == 'input' || $donnie == 'output') { // show input/output data
- $b .= "
" . ucfirst($donnie) . ': ';
- foreach ($marie as $captain => $tenille) { // loop through data
- if ($captain == 'parts') { // loop thru parts
- $b .= " $captain:
";
- //if(is_array($tenille)){
- foreach ($tenille as $joanie => $chachi) {
- $b .= " $joanie: $chachi
";
- }
- //}
- } else {
- $b .= " $captain: $tenille
";
- }
- }
- } else {
- $b .= "
" . ucfirst($donnie) . ": $marie
";
- }
- }
- $b .= '
';
- }
- $b .= '
-
-
';
- return $b;
- }
-
- /**
- * serialize the parsed wsdl
- *
- * @param mixed $debug whether to put debug=1 in endpoint URL
- * @return string serialization of WSDL
- * @access public
- */
- function serialize($debug = 0)
- {
- $xml = '';
- $xml .= "\nnamespaces as $k => $v) {
- $xml .= " xmlns:$k=\"$v\"";
- }
- // 10.9.02 - add poulter fix for wsdl and tns declarations
- if (isset($this->namespaces['wsdl'])) {
- $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
- }
- if (isset($this->namespaces['tns'])) {
- $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
- }
- $xml .= '>';
- // imports
- if (sizeof($this->import) > 0) {
- foreach ($this->import as $ns => $list) {
- foreach ($list as $ii) {
- if ($ii['location'] != '') {
- $xml .= ' ';
- } else {
- $xml .= ' ';
- }
- }
- }
- }
- // types
- if (count($this->schemas) >= 1) {
- $xml .= "\n\n";
- foreach ($this->schemas as $ns => $list) {
- foreach ($list as $xs) {
- $xml .= $xs->serializeSchema();
- }
- }
- $xml .= ' ';
- }
- // messages
- if (count($this->messages) >= 1) {
- foreach ($this->messages as $msgName => $msgParts) {
- $xml .= "\n';
- if (is_array($msgParts)) {
- foreach ($msgParts as $partName => $partType) {
- // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.' ';
- if (strpos($partType, ':')) {
- $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType));
- } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
- // print 'checking typemap: '.$this->XMLSchemaVersion.' ';
- $typePrefix = 'xsd';
- } else {
- foreach ($this->typemap as $ns => $types) {
- if (isset($types[$partType])) {
- $typePrefix = $this->getPrefixFromNamespace($ns);
- }
- }
- if (!isset($typePrefix)) {
- die("$partType has no namespace!");
- }
- }
- $ns = $this->getNamespaceFromPrefix($typePrefix);
- $localPart = $this->getLocalPart($partType);
- $typeDef = $this->getTypeDef($localPart, $ns);
- if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
- $elementortype = 'element';
- if (substr($localPart, -1) == '^') {
- $localPart = substr($localPart, 0, -1);
- }
- } else {
- $elementortype = 'type';
- }
- $xml .= "\n" . ' ';
- }
- }
- $xml .= ' ';
- }
- }
- // bindings & porttypes
- if (count($this->bindings) >= 1) {
- $binding_xml = '';
- $portType_xml = '';
- foreach ($this->bindings as $bindingName => $attrs) {
- $binding_xml .= "\n';
- $binding_xml .= "\n" . ' ';
- $portType_xml .= "\n';
- foreach ($attrs['operations'] as $opName => $opParts) {
- $binding_xml .= "\n" . ' ';
- $binding_xml .= "\n" . ' ';
- if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') {
- $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
- } else {
- $enc_style = '';
- }
- $binding_xml .= "\n" . ' ';
- if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') {
- $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
- } else {
- $enc_style = '';
- }
- $binding_xml .= "\n" . ' ';
- $binding_xml .= "\n" . ' ';
- $portType_xml .= "\n" . ' ' . htmlspecialchars($opParts['documentation']) . '';
- }
- $portType_xml .= "\n" . ' ';
- $portType_xml .= "\n" . ' ';
- $portType_xml .= "\n" . ' ';
- }
- $portType_xml .= "\n" . ' ';
- $binding_xml .= "\n" . ' ';
- }
- $xml .= $portType_xml . $binding_xml;
- }
- // services
- $xml .= "\nserviceName . '">';
- if (count($this->ports) >= 1) {
- foreach ($this->ports as $pName => $attrs) {
- $xml .= "\n" . ' ';
- $xml .= "\n" . ' ';
- $xml .= "\n" . ' ';
- }
- }
- $xml .= "\n" . ' ';
- return $xml . "\n ";
- }
-
- /**
- * determine whether a set of parameters are unwrapped
- * when they are expect to be wrapped, Microsoft-style.
- *
- * @param string $type the type (element name) of the wrapper
- * @param array $parameters the parameter values for the SOAP call
- * @return boolean whether they parameters are unwrapped (and should be wrapped)
- * @access private
- */
- function parametersMatchWrapped($type, &$parameters)
- {
- $this->debug("in parametersMatchWrapped type=$type, parameters=");
- $this->appendDebug($this->varDump($parameters));
-
- // split type into namespace:unqualified-type
- if (strpos($type, ':')) {
- $uqType = substr($type, strrpos($type, ':') + 1);
- $ns = substr($type, 0, strrpos($type, ':'));
- $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
- if ($this->getNamespaceFromPrefix($ns)) {
- $ns = $this->getNamespaceFromPrefix($ns);
- $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
- }
- } else {
- // TODO: should the type be compared to types in XSD, and the namespace
- // set to XSD if the type matches?
- $this->debug("in parametersMatchWrapped: No namespace for type $type");
- $ns = '';
- $uqType = $type;
- }
-
- // get the type information
- if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
- $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
- return false;
- }
- $this->debug("in parametersMatchWrapped: found typeDef=");
- $this->appendDebug($this->varDump($typeDef));
- if (substr($uqType, -1) == '^') {
- $uqType = substr($uqType, 0, -1);
- }
- $phpType = $typeDef['phpType'];
- $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
- $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
-
- // we expect a complexType or element of complexType
- if ($phpType != 'struct') {
- $this->debug("in parametersMatchWrapped: not a struct");
- return false;
- }
-
- // see whether the parameter names match the elements
- if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
- $elements = 0;
- $matches = 0;
- foreach ($typeDef['elements'] as $name => $attrs) {
- if (isset($parameters[$name])) {
- $this->debug("in parametersMatchWrapped: have parameter named $name");
- $matches++;
- } else {
- $this->debug("in parametersMatchWrapped: do not have parameter named $name");
- }
- $elements++;
- }
-
- $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
- if ($matches == 0) {
- return false;
- }
- return true;
- }
-
- // since there are no elements for the type, if the user passed no
- // parameters, the parameters match wrapped.
- $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
- return count($parameters) == 0;
- }
-
- /**
- * serialize PHP values according to a WSDL message definition
- * contrary to the method name, this is not limited to RPC
- *
- * TODO
- * - multi-ref serialization
- * - validate PHP values against type definitions, return errors if invalid
- *
- * @param string $operation operation name
- * @param string $direction (input|output)
- * @param mixed $parameters parameter value(s)
- * @param string $bindingType (soap|soap12)
- * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
- * @access public
- */
- function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap')
- {
- $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
- $this->appendDebug('parameters=' . $this->varDump($parameters));
-
- if ($direction != 'input' && $direction != 'output') {
- $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
- $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
- return false;
- }
- if (!$opData = $this->getOperationData($operation, $bindingType)) {
- $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
- $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
- return false;
- }
- $this->debug('in serializeRPCParameters: opData:');
- $this->appendDebug($this->varDump($opData));
-
- // Get encoding style for output and set to current
- $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
- if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
- $encodingStyle = $opData['output']['encodingStyle'];
- $enc_style = $encodingStyle;
- }
-
- // set input params
- $xml = '';
- if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
- $parts = &$opData[$direction]['parts'];
- $part_count = sizeof($parts);
- $style = $opData['style'];
- $use = $opData[$direction]['use'];
- $this->debug("have $part_count part(s) to serialize using $style/$use");
- if (is_array($parameters)) {
- $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
- $parameter_count = count($parameters);
- $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
- // check for Microsoft-style wrapped parameters
- if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) {
- $this->debug('check whether the caller has wrapped the parameters');
- if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) {
- // TODO: consider checking here for double-wrapping, when
- // service function wraps, then NuSOAP wraps again
- $this->debug("change simple array to associative with 'parameters' element");
- $parameters['parameters'] = $parameters[0];
- unset($parameters[0]);
- }
- if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) {
- $this->debug('check whether caller\'s parameters match the wrapped ones');
- if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
- $this->debug('wrap the parameters for the caller');
- $parameters = array('parameters' => $parameters);
- $parameter_count = 1;
- }
- }
- }
- foreach ($parts as $name => $type) {
- $this->debug("serializing part $name of type $type");
- // Track encoding style
- if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
- $encodingStyle = $opData[$direction]['encodingStyle'];
- $enc_style = $encodingStyle;
- } else {
- $enc_style = false;
- }
- // NOTE: add error handling here
- // if serializeType returns false, then catch global error and fault
- if ($parametersArrayType == 'arraySimple') {
- $p = array_shift($parameters);
- $this->debug('calling serializeType w/indexed param');
- $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
- } elseif (isset($parameters[$name])) {
- $this->debug('calling serializeType w/named param');
- $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
- } else {
- // TODO: only send nillable
- $this->debug('calling serializeType w/null param');
- $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
- }
- }
- } else {
- $this->debug('no parameters passed.');
- }
- }
- $this->debug("serializeRPCParameters returning: $xml");
- return $xml;
- }
-
- /**
- * serialize a PHP value according to a WSDL message definition
- *
- * TODO
- * - multi-ref serialization
- * - validate PHP values against type definitions, return errors if invalid
- *
- * @param string $operation operation name
- * @param string $direction (input|output)
- * @param mixed $parameters parameter value(s)
- * @return mixed parameters serialized as XML or false on error (e.g. operation not found)
- * @access public
- * @deprecated
- */
- function serializeParameters($operation, $direction, $parameters)
- {
- $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
- $this->appendDebug('parameters=' . $this->varDump($parameters));
-
- if ($direction != 'input' && $direction != 'output') {
- $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
- $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
- return false;
- }
- if (!$opData = $this->getOperationData($operation)) {
- $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
- $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
- return false;
- }
- $this->debug('opData:');
- $this->appendDebug($this->varDump($opData));
-
- // Get encoding style for output and set to current
- $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
- if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) {
- $encodingStyle = $opData['output']['encodingStyle'];
- $enc_style = $encodingStyle;
- }
-
- // set input params
- $xml = '';
- if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) {
-
- $use = $opData[$direction]['use'];
- $this->debug("use=$use");
- $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
- if (is_array($parameters)) {
- $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
- $this->debug('have ' . $parametersArrayType . ' parameters');
- foreach ($opData[$direction]['parts'] as $name => $type) {
- $this->debug('serializing part "' . $name . '" of type "' . $type . '"');
- // Track encoding style
- if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) {
- $encodingStyle = $opData[$direction]['encodingStyle'];
- $enc_style = $encodingStyle;
- } else {
- $enc_style = false;
- }
- // NOTE: add error handling here
- // if serializeType returns false, then catch global error and fault
- if ($parametersArrayType == 'arraySimple') {
- $p = array_shift($parameters);
- $this->debug('calling serializeType w/indexed param');
- $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
- } elseif (isset($parameters[$name])) {
- $this->debug('calling serializeType w/named param');
- $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
- } else {
- // TODO: only send nillable
- $this->debug('calling serializeType w/null param');
- $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
- }
- }
- } else {
- $this->debug('no parameters passed.');
- }
- }
- $this->debug("serializeParameters returning: $xml");
- return $xml;
- }
-
- /**
- * serializes a PHP value according a given type definition
- *
- * @param string $name name of value (part or element)
- * @param string $type XML schema type of value (type or element)
- * @param mixed $value a native PHP value (parameter value)
- * @param string $use use for part (encoded|literal)
- * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
- * @param boolean $unqualified a kludge for what should be XML namespace form handling
- * @return string value serialized as an XML string
- * @access private
- */
- function serializeType($name, $type, $value, $use = 'encoded', $encodingStyle = false, $unqualified = false)
- {
- $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified"));
- $this->appendDebug("value=" . $this->varDump($value));
- if ($use == 'encoded' && $encodingStyle) {
- $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
- }
-
- // if a soapval has been supplied, let its type override the WSDL
- if (is_object($value) && get_class($value) == 'soapval') {
- if ($value->type_ns) {
- $type = $value->type_ns . ':' . $value->type;
- $forceType = true;
- $this->debug("in serializeType: soapval overrides type to $type");
- } elseif ($value->type) {
- $type = $value->type;
- $forceType = true;
- $this->debug("in serializeType: soapval overrides type to $type");
- } else {
- $forceType = false;
- $this->debug("in serializeType: soapval does not override type");
- }
- $attrs = $value->attributes;
- $value = $value->value;
- $this->debug("in serializeType: soapval overrides value to $value");
- if ($attrs) {
- if (!is_array($value)) {
- $value['!'] = $value;
- }
- foreach ($attrs as $n => $v) {
- $value['!' . $n] = $v;
- }
- $this->debug("in serializeType: soapval provides attributes");
- }
- } else {
- $forceType = false;
- }
-
- $xml = '';
- if (strpos($type, ':')) {
- $uqType = substr($type, strrpos($type, ':') + 1);
- $ns = substr($type, 0, strrpos($type, ':'));
- $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
- if ($this->getNamespaceFromPrefix($ns)) {
- $ns = $this->getNamespaceFromPrefix($ns);
- $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
- }
-
- if ($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/') {
- $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
- if ($unqualified && $use == 'literal') {
- $elementNS = " xmlns=\"\"";
- } else {
- $elementNS = '';
- }
- if (is_null($value)) {
- if ($use == 'literal') {
- // TODO: depends on minOccurs
- $xml = "<$name$elementNS/>";
- } else {
- // TODO: depends on nillable, which should be checked before calling this method
- $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
- }
- $this->debug("in serializeType: returning: $xml");
- return $xml;
- }
- if ($uqType == 'Array') {
- // JBoss/Axis does this sometimes
- return $this->serialize_val($value, $name, false, false, false, false, $use);
- }
- if ($uqType == 'boolean') {
- if ((is_string($value) && $value == 'false') || (!$value)) {
- $value = 'false';
- } else {
- $value = 'true';
- }
- }
- if ($uqType == 'string' && gettype($value) == 'string') {
- $value = $this->expandEntities($value);
- }
- if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') {
- $value = sprintf("%.0lf", $value);
- }
- // it's a scalar
- // TODO: what about null/nil values?
- // check type isn't a custom type extending xmlschema namespace
- if (!$this->getTypeDef($uqType, $ns)) {
- if ($use == 'literal') {
- if ($forceType) {
- $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value$name>";
- } else {
- $xml = "<$name$elementNS>$value$name>";
- }
- } else {
- $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value$name>";
- }
- $this->debug("in serializeType: returning: $xml");
- return $xml;
- }
- $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
- } elseif ($ns == 'http://xml.apache.org/xml-soap') {
- $this->debug('in serializeType: appears to be Apache SOAP type');
- if ($uqType == 'Map') {
- $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
- if (!$tt_prefix) {
- $this->debug('in serializeType: Add namespace for Apache SOAP type');
- $tt_prefix = 'ns' . rand(1000, 9999);
- $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
- // force this to be added to usedNamespaces
- $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
- }
- $contents = '';
- foreach ($value as $k => $v) {
- $this->debug("serializing map element: key $k, value $v");
- $contents .= '- ';
- $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use);
- $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use);
- $contents .= '
';
- }
- if ($use == 'literal') {
- if ($forceType) {
- $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents$name>";
- } else {
- $xml = "<$name>$contents$name>";
- }
- } else {
- $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents$name>";
- }
- $this->debug("in serializeType: returning: $xml");
- return $xml;
- }
- $this->debug('in serializeType: Apache SOAP type, but only support Map');
- }
- } else {
- // TODO: should the type be compared to types in XSD, and the namespace
- // set to XSD if the type matches?
- $this->debug("in serializeType: No namespace for type $type");
- $ns = '';
- $uqType = $type;
- }
- if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
- $this->setError("$type ($uqType) is not a supported type.");
- $this->debug("in serializeType: $type ($uqType) is not a supported type.");
- return false;
- } else {
- $this->debug("in serializeType: found typeDef");
- $this->appendDebug('typeDef=' . $this->varDump($typeDef));
- if (substr($uqType, -1) == '^') {
- $uqType = substr($uqType, 0, -1);
- }
- }
- if (!isset($typeDef['phpType'])) {
- $this->setError("$type ($uqType) has no phpType.");
- $this->debug("in serializeType: $type ($uqType) has no phpType.");
- return false;
- }
- $phpType = $typeDef['phpType'];
- $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''));
- // if php type == struct, map value to the element names
- if ($phpType == 'struct') {
- if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') {
- $elementName = $uqType;
- if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
- $elementNS = " xmlns=\"$ns\"";
- } else {
- $elementNS = " xmlns=\"\"";
- }
- } else {
- $elementName = $name;
- if ($unqualified) {
- $elementNS = " xmlns=\"\"";
- } else {
- $elementNS = '';
- }
- }
- if (is_null($value)) {
- if ($use == 'literal') {
- // TODO: depends on minOccurs and nillable
- $xml = "<$elementName$elementNS/>";
- } else {
- $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
- }
- $this->debug("in serializeType: returning: $xml");
- return $xml;
- }
- if (is_object($value)) {
- $value = get_object_vars($value);
- }
- if (is_array($value)) {
- $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
- if ($use == 'literal') {
- if ($forceType) {
- $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
- } else {
- $xml = "<$elementName$elementNS$elementAttrs>";
- }
- } else {
- $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
- }
-
- if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') {
- if (isset($value['!'])) {
- $xml .= $value['!'];
- $this->debug("in serializeType: serialized simpleContent for type $type");
- } else {
- $this->debug("in serializeType: no simpleContent to serialize for type $type");
- }
- } else {
- // complexContent
- $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
- }
- $xml .= "$elementName>";
- } else {
- $this->debug("in serializeType: phpType is struct, but value is not an array");
- $this->setError("phpType is struct, but value is not an array: see debug output for details");
- $xml = '';
- }
- } elseif ($phpType == 'array') {
- if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
- $elementNS = " xmlns=\"$ns\"";
- } else {
- if ($unqualified) {
- $elementNS = " xmlns=\"\"";
- } else {
- $elementNS = '';
- }
- }
- if (is_null($value)) {
- if ($use == 'literal') {
- // TODO: depends on minOccurs
- $xml = "<$name$elementNS/>";
- } else {
- $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" .
- $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
- ":Array\" " .
- $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .
- ':arrayType="' .
- $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .
- ':' .
- $this->getLocalPart($typeDef['arrayType']) . "[0]\"/>";
- }
- $this->debug("in serializeType: returning: $xml");
- return $xml;
- }
- if (isset($typeDef['multidimensional'])) {
- $nv = array();
- foreach ($value as $v) {
- $cols = ',' . sizeof($v);
- $nv = array_merge($nv, $v);
- }
- $value = $nv;
- } else {
- $cols = '';
- }
- if (is_array($value) && sizeof($value) >= 1) {
- $rows = sizeof($value);
- $contents = '';
- foreach ($value as $k => $v) {
- //$this->debug breaks when serializing ArrayOfComplexType
- //Error: Object of class [COMPLEX-TYPE] could not be converted to string
- //$this->debug("serializing array element: $k, " . (is_array($v) ? "array" : $v) . " of type: $typeDef[arrayType]");
- //if (strpos($typeDef['arrayType'], ':') ) {
- if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) {
- $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
- } else {
- $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
- }
- }
- } else {
- $rows = 0;
- $contents = null;
- }
- // TODO: for now, an empty value will be serialized as a zero element
- // array. Revisit this when coding the handling of null/nil values.
- if ($use == 'literal') {
- $xml = "<$name$elementNS>"
- . $contents
- . "$name>";
- } else {
- $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':Array" ' .
- $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
- . ':arrayType="'
- . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType']))
- . ":" . $this->getLocalPart($typeDef['arrayType']) . "[$rows$cols]\">"
- . $contents
- . "$name>";
- }
- } elseif ($phpType == 'scalar') {
- if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) {
- $elementNS = " xmlns=\"$ns\"";
- } else {
- if ($unqualified) {
- $elementNS = " xmlns=\"\"";
- } else {
- $elementNS = '';
- }
- }
- if ($use == 'literal') {
- if ($forceType) {
- $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value$name>";
- } else {
- $xml = "<$name$elementNS>$value$name>";
- }
- } else {
- $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value$name>";
- }
- }
- $this->debug("in serializeType: returning: $xml");
- return $xml;
- }
-
- /**
- * serializes the attributes for a complexType
- *
- * @param array $typeDef our internal representation of an XML schema type (or element)
- * @param mixed $value a native PHP value (parameter value)
- * @param string $ns the namespace of the type
- * @param string $uqType the local part of the type
- * @return string value serialized as an XML string
- * @access private
- */
- function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
- {
- $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
- $xml = '';
- if (isset($typeDef['extensionBase'])) {
- $nsx = $this->getPrefix($typeDef['extensionBase']);
- $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
- if ($this->getNamespaceFromPrefix($nsx)) {
- $nsx = $this->getNamespaceFromPrefix($nsx);
- }
- if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
- $this->debug("serialize attributes for extension base $nsx:$uqTypex");
- $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
- } else {
- $this->debug("extension base $nsx:$uqTypex is not a supported type");
- }
- }
- if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
- $this->debug("serialize attributes for XML Schema type $ns:$uqType");
- if (is_array($value)) {
- $xvalue = $value;
- } elseif (is_object($value)) {
- $xvalue = get_object_vars($value);
- } else {
- $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
- $xvalue = array();
- }
- foreach ($typeDef['attrs'] as $aName => $attrs) {
- if (isset($xvalue['!' . $aName])) {
- $xname = '!' . $aName;
- $this->debug("value provided for attribute $aName with key $xname");
- } elseif (isset($xvalue[$aName])) {
- $xname = $aName;
- $this->debug("value provided for attribute $aName with key $xname");
- } elseif (isset($attrs['default'])) {
- $xname = '!' . $aName;
- $xvalue[$xname] = $attrs['default'];
- $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
- } else {
- $xname = '';
- $this->debug("no value provided for attribute $aName");
- }
- if ($xname) {
- $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
- }
- }
- } else {
- $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
- }
- return $xml;
- }
-
- /**
- * serializes the elements for a complexType
- *
- * @param array $typeDef our internal representation of an XML schema type (or element)
- * @param mixed $value a native PHP value (parameter value)
- * @param string $ns the namespace of the type
- * @param string $uqType the local part of the type
- * @param string $use use for part (encoded|literal)
- * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
- * @return string value serialized as an XML string
- * @access private
- */
- function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use = 'encoded', $encodingStyle = false)
- {
- $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
- $xml = '';
- if (isset($typeDef['extensionBase'])) {
- $nsx = $this->getPrefix($typeDef['extensionBase']);
- $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
- if ($this->getNamespaceFromPrefix($nsx)) {
- $nsx = $this->getNamespaceFromPrefix($nsx);
- }
- if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
- $this->debug("serialize elements for extension base $nsx:$uqTypex");
- $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
- } else {
- $this->debug("extension base $nsx:$uqTypex is not a supported type");
- }
- }
- if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
- $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
- if (is_array($value)) {
- $xvalue = $value;
- } elseif (is_object($value)) {
- $xvalue = get_object_vars($value);
- } else {
- $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
- $xvalue = array();
- }
- // toggle whether all elements are present - ideally should validate against schema
- if (count($typeDef['elements']) != count($xvalue)) {
- $optionals = true;
- }
- foreach ($typeDef['elements'] as $eName => $attrs) {
- if (!isset($xvalue[$eName])) {
- if (isset($attrs['default'])) {
- $xvalue[$eName] = $attrs['default'];
- $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
- }
- }
- // if user took advantage of a minOccurs=0, then only serialize named parameters
- if (isset($optionals)
- && (!isset($xvalue[$eName]))
- && ((!isset($attrs['nillable'])) || $attrs['nillable'] != 'true')
- ) {
- if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
- $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
- }
- // do nothing
- $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
- } else {
- // get value
- if (isset($xvalue[$eName])) {
- $v = $xvalue[$eName];
- } else {
- $v = null;
- }
- if (isset($attrs['form'])) {
- $unqualified = ($attrs['form'] == 'unqualified');
- } else {
- $unqualified = false;
- }
- if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') {
- $vv = $v;
- foreach ($vv as $k => $v) {
- if (isset($attrs['type']) || isset($attrs['ref'])) {
- // serialize schema-defined type
- $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
- } else {
- // serialize generic type (can this ever really happen?)
- $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
- $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
- }
- }
- } else {
- if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') {
- // do nothing
- } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') {
- // TODO: serialize a nil correctly, but for now serialize schema-defined type
- $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
- } elseif (isset($attrs['type']) || isset($attrs['ref'])) {
- // serialize schema-defined type
- $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
- } else {
- // serialize generic type (can this ever really happen?)
- $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
- $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
- }
- }
- }
- }
- } else {
- $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
- }
- return $xml;
- }
-
- /**
- * adds an XML Schema complex type to the WSDL types
- *
- * @param string $name
- * @param string $typeClass (complexType|simpleType|attribute)
- * @param string $phpType currently supported are array and struct (php assoc array)
- * @param string $compositor (all|sequence|choice)
- * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
- * @param array $elements e.g. array ( name => array(name=>'',type=>'') )
- * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
- * @param string $arrayType as namespace:name (xsd:string)
- * @see nusoap_xmlschema
- * @access public
- */
- function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '')
- {
- if (count($elements) > 0) {
- $eElements = array();
- foreach ($elements as $n => $e) {
- // expand each element
- $ee = array();
- foreach ($e as $k => $v) {
- $k = strpos($k, ':') ? $this->expandQname($k) : $k;
- $v = strpos($v, ':') ? $this->expandQname($v) : $v;
- $ee[$k] = $v;
- }
- $eElements[$n] = $ee;
- }
- $elements = $eElements;
- }
-
- if (count($attrs) > 0) {
- foreach ($attrs as $n => $a) {
- // expand each attribute
- foreach ($a as $k => $v) {
- $k = strpos($k, ':') ? $this->expandQname($k) : $k;
- $v = strpos($v, ':') ? $this->expandQname($v) : $v;
- $aa[$k] = $v;
- }
- $eAttrs[$n] = $aa;
- }
- $attrs = $eAttrs;
- }
-
- $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
- $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType;
-
- $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
- $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType);
- }
-
- /**
- * adds an XML Schema simple type to the WSDL types
- *
- * @param string $name
- * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
- * @param string $typeClass (should always be simpleType)
- * @param string $phpType (should always be scalar)
- * @param array $enumeration array of values
- * @see nusoap_xmlschema
- * @access public
- */
- function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array())
- {
- $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
-
- $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
- $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
- }
-
- /**
- * adds an element to the WSDL types
- *
- * @param array $attrs attributes that must include name and type
- * @see nusoap_xmlschema
- * @access public
- */
- function addElement($attrs)
- {
- $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
- $this->schemas[$typens][0]->addElement($attrs);
- }
-
- /**
- * register an operation with the server
- *
- * @param string $name operation (method) name
- * @param array $in assoc array of input values: key = param name, value = param type
- * @param array $out assoc array of output values: key = param name, value = param type
- * @param string $namespace optional The namespace for the operation
- * @param string $soapaction optional The soapaction for the operation
- * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically
- * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now)
- * @param string $documentation optional The description to include in the WSDL
- * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
- * @access public
- */
- function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '')
- {
- if ($use == 'encoded' && $encodingStyle == '') {
- $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
- }
-
- if ($style == 'document') {
- $elements = array();
- foreach ($in as $n => $t) {
- $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
- }
- $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
- $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
- $in = array('parameters' => 'tns:' . $name . '^');
-
- $elements = array();
- foreach ($out as $n => $t) {
- $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
- }
- $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
- $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified'));
- $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
- }
-
- // get binding
- $this->bindings[$this->serviceName . 'Binding']['operations'][$name] =
- array(
- 'name' => $name,
- 'binding' => $this->serviceName . 'Binding',
- 'endpoint' => $this->endpoint,
- 'soapAction' => $soapaction,
- 'style' => $style,
- 'input' => array(
- 'use' => $use,
- 'namespace' => $namespace,
- 'encodingStyle' => $encodingStyle,
- 'message' => $name . 'Request',
- 'parts' => $in),
- 'output' => array(
- 'use' => $use,
- 'namespace' => $namespace,
- 'encodingStyle' => $encodingStyle,
- 'message' => $name . 'Response',
- 'parts' => $out),
- 'namespace' => $namespace,
- 'transport' => 'http://schemas.xmlsoap.org/soap/http',
- 'documentation' => $documentation);
- // add portTypes
- // add messages
- if ($in) {
- foreach ($in as $pName => $pType) {
- if (strpos($pType, ':')) {
- $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
- }
- $this->messages[$name . 'Request'][$pName] = $pType;
- }
- } else {
- $this->messages[$name . 'Request'] = '0';
- }
- if ($out) {
- foreach ($out as $pName => $pType) {
- if (strpos($pType, ':')) {
- $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType);
- }
- $this->messages[$name . 'Response'][$pName] = $pType;
- }
- } else {
- $this->messages[$name . 'Response'] = '0';
- }
- return true;
- }
-}
-
-
-/**
- *
- * nusoap_parser class parses SOAP XML messages into native PHP values
- *
- * @author Dietrich Ayala
- * @author Scott Nichol
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class nusoap_parser extends nusoap_base
-{
-
- var $xml = '';
- var $xml_encoding = '';
- var $method = '';
- var $root_struct = '';
- var $root_struct_name = '';
- var $root_struct_namespace = '';
- var $root_header = '';
- var $document = ''; // incoming SOAP body (text)
- // determines where in the message we are (envelope,header,body,method)
- var $status = '';
- var $position = 0;
- var $depth = 0;
- var $default_namespace = '';
- var $namespaces = array();
- var $message = array();
- var $parent = '';
- var $fault = false;
- var $fault_code = '';
- var $fault_str = '';
- var $fault_detail = '';
- var $depth_array = array();
- var $debug_flag = true;
- var $soapresponse = null; // parsed SOAP Body
- var $soapheader = null; // parsed SOAP Header
- var $responseHeaders = ''; // incoming SOAP headers (text)
- var $body_position = 0;
- // for multiref parsing:
- // array of id => pos
- var $ids = array();
- // array of id => hrefs => pos
- var $multirefs = array();
- // toggle for auto-decoding element content
- var $decode_utf8 = true;
-
- /**
- * constructor that actually does the parsing
- *
- * @param string $xml SOAP message
- * @param string $encoding character encoding scheme of message
- * @param string $method method for which XML is parsed (unused?)
- * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
- * @access public
- */
- function __construct($xml, $encoding = 'UTF-8', $method = '', $decode_utf8 = true)
- {
- parent::__construct();
- $this->xml = $xml;
- $this->xml_encoding = $encoding;
- $this->method = $method;
- $this->decode_utf8 = $decode_utf8;
-
- // Check whether content has been read.
- if (!empty($xml)) {
- // Check XML encoding
- $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1);
- if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
- $xml_encoding = $res[1];
- if (strtoupper($xml_encoding) != $encoding) {
- $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
- $this->debug($err);
- if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') {
- $this->setError($err);
- return;
- }
- // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
- } else {
- $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
- }
- } else {
- $this->debug('No encoding specified in XML declaration');
- }
- } else {
- $this->debug('No XML declaration');
- }
- $this->debug('Entering nusoap_parser(), length=' . strlen($xml) . ', encoding=' . $encoding);
- // Create an XML parser - why not xml_parser_create_ns?
- $this->parser = xml_parser_create($this->xml_encoding);
- // Set the options for parsing the XML data.
- //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
- xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
- xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
- // Set the object for the parser.
- xml_set_object($this->parser, $this);
- // Set the element handlers for the parser.
- xml_set_element_handler($this->parser, 'start_element', 'end_element');
- xml_set_character_data_handler($this->parser, 'character_data');
- $parseErrors = array();
- $chunkSize = 4096;
- for($pointer = 0; $pointer < strlen($xml) && empty($parseErrors); $pointer += $chunkSize) {
- $xmlString = substr($xml, $pointer, $chunkSize);
- if(!xml_parse($this->parser, $xmlString, false)) {
- $parseErrors['lineNumber'] = xml_get_current_line_number($this->parser);
- $parseErrors['errorString'] = xml_error_string(xml_get_error_code($this->parser));
- };
- }
- //Tell the script that is the end of the parsing (by setting is_final to TRUE)
- xml_parse($this->parser, '', true);
-
- if(!empty($parseErrors)){
- // Display an error message.
- $err = sprintf('XML error parsing SOAP payload on line %d: %s',
- $parseErrors['lineNumber'],
- $parseErrors['errorString']);
- $this->debug($err);
- $this->setError($err);
- } else {
- $this->debug('in nusoap_parser ctor, message:');
- $this->appendDebug($this->varDump($this->message));
- $this->debug('parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name);
- // get final value
- $this->soapresponse = $this->message[$this->root_struct]['result'];
- // get header value
- if ($this->root_header != '' && isset($this->message[$this->root_header]['result'])) {
- $this->soapheader = $this->message[$this->root_header]['result'];
- }
- // resolve hrefs/ids
- if (sizeof($this->multirefs) > 0) {
- foreach ($this->multirefs as $id => $hrefs) {
- $this->debug('resolving multirefs for id: ' . $id);
- $idVal = $this->buildVal($this->ids[$id]);
- if (is_array($idVal) && isset($idVal['!id'])) {
- unset($idVal['!id']);
- }
- foreach ($hrefs as $refPos => $ref) {
- $this->debug('resolving href at pos ' . $refPos);
- $this->multirefs[$id][$refPos] = $idVal;
- }
- }
- }
- }
- xml_parser_free($this->parser);
- unset($this->parser);
- } else {
- $this->debug('xml was empty, didn\'t parse!');
- $this->setError('xml was empty, didn\'t parse!');
- }
- }
-
- /**
- * start-element handler
- *
- * @param resource $parser XML parser object
- * @param string $name element name
- * @param array $attrs associative array of attributes
- * @access private
- */
- function start_element($parser, $name, $attrs)
- {
- // position in a total number of elements, starting from 0
- // update class level pos
- $pos = $this->position++;
- // and set mine
- $this->message[$pos] = array('pos' => $pos, 'children' => '', 'cdata' => '');
- // depth = how many levels removed from root?
- // set mine as current global depth and increment global depth value
- $this->message[$pos]['depth'] = $this->depth++;
-
- // else add self as child to whoever the current parent is
- if ($pos != 0) {
- $this->message[$this->parent]['children'] .= '|' . $pos;
- }
- // set my parent
- $this->message[$pos]['parent'] = $this->parent;
- // set self as current parent
- $this->parent = $pos;
- // set self as current value for this depth
- $this->depth_array[$this->depth] = $pos;
- // get element prefix
- if (strpos($name, ':')) {
- // get ns prefix
- $prefix = substr($name, 0, strpos($name, ':'));
- // get unqualified name
- $name = substr(strstr($name, ':'), 1);
- }
- // set status
- if ($name == 'Envelope' && $this->status == '') {
- $this->status = 'envelope';
- } elseif ($name == 'Header' && $this->status == 'envelope') {
- $this->root_header = $pos;
- $this->status = 'header';
- } elseif ($name == 'Body' && $this->status == 'envelope') {
- $this->status = 'body';
- $this->body_position = $pos;
- // set method
- } elseif ($this->status == 'body' && $pos == ($this->body_position + 1)) {
- $this->status = 'method';
- $this->root_struct_name = $name;
- $this->root_struct = $pos;
- $this->message[$pos]['type'] = 'struct';
- $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
- }
- // set my status
- $this->message[$pos]['status'] = $this->status;
- // set name
- $this->message[$pos]['name'] = htmlspecialchars($name);
- // set attrs
- $this->message[$pos]['attrs'] = $attrs;
-
- // loop through atts, logging ns and type declarations
- $attstr = '';
- foreach ($attrs as $key => $value) {
- $key_prefix = $this->getPrefix($key);
- $key_localpart = $this->getLocalPart($key);
- // if ns declarations, add to class level array of valid namespaces
- if ($key_prefix == 'xmlns') {
- if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) {
- $this->XMLSchemaVersion = $value;
- $this->namespaces['xsd'] = $this->XMLSchemaVersion;
- $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
- }
- $this->namespaces[$key_localpart] = $value;
- // set method namespace
- if ($name == $this->root_struct_name) {
- $this->methodNamespace = $value;
- }
- // if it's a type declaration, set type
- } elseif ($key_localpart == 'type') {
- if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') {
- // do nothing: already processed arrayType
- } else {
- $value_prefix = $this->getPrefix($value);
- $value_localpart = $this->getLocalPart($value);
- $this->message[$pos]['type'] = $value_localpart;
- $this->message[$pos]['typePrefix'] = $value_prefix;
- if (isset($this->namespaces[$value_prefix])) {
- $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
- } elseif (isset($attrs['xmlns:' . $value_prefix])) {
- $this->message[$pos]['type_namespace'] = $attrs['xmlns:' . $value_prefix];
- }
- // should do something here with the namespace of specified type?
- }
- } elseif ($key_localpart == 'arrayType') {
- $this->message[$pos]['type'] = 'array';
- /* do arrayType ereg here
- [1] arrayTypeValue ::= atype asize
- [2] atype ::= QName rank*
- [3] rank ::= '[' (',')* ']'
- [4] asize ::= '[' length~ ']'
- [5] length ::= nextDimension* Digit+
- [6] nextDimension ::= Digit+ ','
- */
- $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
- if (preg_match($expr, $value, $regs)) {
- $this->message[$pos]['typePrefix'] = $regs[1];
- $this->message[$pos]['arrayTypePrefix'] = $regs[1];
- if (isset($this->namespaces[$regs[1]])) {
- $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
- } elseif (isset($attrs['xmlns:' . $regs[1]])) {
- $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:' . $regs[1]];
- }
- $this->message[$pos]['arrayType'] = $regs[2];
- $this->message[$pos]['arraySize'] = $regs[3];
- $this->message[$pos]['arrayCols'] = $regs[4];
- }
- // specifies nil value (or not)
- } elseif ($key_localpart == 'nil') {
- $this->message[$pos]['nil'] = ($value == 'true' || $value == '1');
- // some other attribute
- } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') {
- $this->message[$pos]['xattrs']['!' . $key] = $value;
- }
-
- if ($key == 'xmlns') {
- $this->default_namespace = $value;
- }
- // log id
- if ($key == 'id') {
- $this->ids[$value] = $pos;
- }
- // root
- if ($key_localpart == 'root' && $value == 1) {
- $this->status = 'method';
- $this->root_struct_name = $name;
- $this->root_struct = $pos;
- $this->debug("found root struct $this->root_struct_name, pos $pos");
- }
- // for doclit
- $attstr .= " $key=\"$value\"";
- }
- // get namespace - must be done after namespace atts are processed
- if (isset($prefix)) {
- $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
- $this->default_namespace = $this->namespaces[$prefix];
- } else {
- $this->message[$pos]['namespace'] = $this->default_namespace;
- }
- if ($this->status == 'header') {
- if ($this->root_header != $pos) {
- $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
- }
- } elseif ($this->root_struct_name != '') {
- $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
- }
- }
-
- /**
- * end-element handler
- *
- * @param resource $parser XML parser object
- * @param string $name element name
- * @access private
- */
- function end_element($parser, $name)
- {
- // position of current element is equal to the last value left in depth_array for my depth
- $pos = $this->depth_array[$this->depth--];
-
- // get element prefix
- if (strpos($name, ':')) {
- // get ns prefix
- $prefix = substr($name, 0, strpos($name, ':'));
- // get unqualified name
- $name = substr(strstr($name, ':'), 1);
- }
-
- // build to native type
- if (isset($this->body_position) && $pos > $this->body_position) {
- // deal w/ multirefs
- if (isset($this->message[$pos]['attrs']['href'])) {
- // get id
- $id = substr($this->message[$pos]['attrs']['href'], 1);
- // add placeholder to href array
- $this->multirefs[$id][$pos] = 'placeholder';
- // add set a reference to it as the result value
- $this->message[$pos]['result'] =& $this->multirefs[$id][$pos];
- // build complexType values
- } elseif ($this->message[$pos]['children'] != '') {
- // if result has already been generated (struct/array)
- if (!isset($this->message[$pos]['result'])) {
- $this->message[$pos]['result'] = $this->buildVal($pos);
- }
- // build complexType values of attributes and possibly simpleContent
- } elseif (isset($this->message[$pos]['xattrs'])) {
- if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
- $this->message[$pos]['xattrs']['!'] = null;
- } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
- if (isset($this->message[$pos]['type'])) {
- $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
- } else {
- $parent = $this->message[$pos]['parent'];
- if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
- $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
- } else {
- $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
- }
- }
- }
- $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
- // set value of simpleType (or nil complexType)
- } else {
- //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']);
- if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
- $this->message[$pos]['xattrs']['!'] = null;
- } elseif (isset($this->message[$pos]['type'])) {
- $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
- } else {
- $parent = $this->message[$pos]['parent'];
- if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
- $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
- } else {
- $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
- }
- }
-
- /* add value to parent's result, if parent is struct/array
- $parent = $this->message[$pos]['parent'];
- if($this->message[$parent]['type'] != 'map'){
- if(strtolower($this->message[$parent]['type']) == 'array'){
- $this->message[$parent]['result'][] = $this->message[$pos]['result'];
- } else {
- $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
- }
- }
- */
- }
- }
-
- // for doclit
- if ($this->status == 'header') {
- if ($this->root_header != $pos) {
- $this->responseHeaders .= "" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
- }
- } elseif ($pos >= $this->root_struct) {
- $this->document .= "" . (isset($prefix) ? $prefix . ':' : '') . "$name>";
- }
- // switch status
- if ($pos == $this->root_struct) {
- $this->status = 'body';
- $this->root_struct_namespace = $this->message[$pos]['namespace'];
- } elseif ($pos == $this->root_header) {
- $this->status = 'envelope';
- } elseif ($name == 'Body' && $this->status == 'body') {
- $this->status = 'envelope';
- } elseif ($name == 'Header' && $this->status == 'header') { // will never happen
- $this->status = 'envelope';
- } elseif ($name == 'Envelope' && $this->status == 'envelope') {
- $this->status = '';
- }
- // set parent back to my parent
- $this->parent = $this->message[$pos]['parent'];
- }
-
- /**
- * element content handler
- *
- * @param resource $parser XML parser object
- * @param string $data element content
- * @access private
- */
- function character_data($parser, $data)
- {
- $pos = $this->depth_array[$this->depth];
- if ($this->xml_encoding == 'UTF-8') {
- // TODO: add an option to disable this for folks who want
- // raw UTF-8 that, e.g., might not map to iso-8859-1
- // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
- if ($this->decode_utf8) {
- $data = utf8_decode($data);
- }
- }
- $this->message[$pos]['cdata'] .= $data;
- // for doclit
- if ($this->status == 'header') {
- $this->responseHeaders .= $data;
- } else {
- $this->document .= $data;
- }
- }
-
- /**
- * get the parsed message (SOAP Body)
- *
- * @return mixed
- * @access public
- * @deprecated use get_soapbody instead
- */
- function get_response()
- {
- return $this->soapresponse;
- }
-
- /**
- * get the parsed SOAP Body (null if there was none)
- *
- * @return mixed
- * @access public
- */
- function get_soapbody()
- {
- return $this->soapresponse;
- }
-
- /**
- * get the parsed SOAP Header (null if there was none)
- *
- * @return mixed
- * @access public
- */
- function get_soapheader()
- {
- return $this->soapheader;
- }
-
- /**
- * get the unparsed SOAP Header
- *
- * @return string XML or empty if no Header
- * @access public
- */
- function getHeaders()
- {
- return $this->responseHeaders;
- }
-
- /**
- * decodes simple types into PHP variables
- *
- * @param string $value value to decode
- * @param string $type XML type to decode
- * @param string $typens XML type namespace to decode
- * @return mixed PHP value
- * @access private
- */
- function decodeSimple($value, $type, $typens)
- {
- // TODO: use the namespace!
- if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') {
- return (string) $value;
- }
- if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') {
- return (int) $value;
- }
- if ($type == 'float' || $type == 'double' || $type == 'decimal') {
- return (double) $value;
- }
- if ($type == 'boolean') {
- if (strtolower($value) == 'false' || strtolower($value) == 'f') {
- return false;
- }
- return (boolean) $value;
- }
- if ($type == 'base64' || $type == 'base64Binary') {
- $this->debug('Decode base64 value');
- return base64_decode($value);
- }
- // obscure numeric types
- if ($type == 'nonPositiveInteger' || $type == 'negativeInteger'
- || $type == 'nonNegativeInteger' || $type == 'positiveInteger'
- || $type == 'unsignedInt'
- || $type == 'unsignedShort' || $type == 'unsignedByte'
- ) {
- return (int) $value;
- }
- // bogus: parser treats array with no elements as a simple type
- if ($type == 'array') {
- return array();
- }
- // everything else
- return (string) $value;
- }
-
- /**
- * builds response structures for compound values (arrays/structs)
- * and scalars
- *
- * @param integer $pos position in node tree
- * @return mixed PHP value
- * @access private
- */
- function buildVal($pos)
- {
- if (!isset($this->message[$pos]['type'])) {
- $this->message[$pos]['type'] = '';
- }
- $this->debug('in buildVal() for ' . $this->message[$pos]['name'] . "(pos $pos) of type " . $this->message[$pos]['type']);
- // if there are children...
- if ($this->message[$pos]['children'] != '') {
- $params = [];
- $this->debug('in buildVal, there are children');
- $children = explode('|', $this->message[$pos]['children']);
- array_shift($children); // knock off empty
- // md array
- if (isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != '') {
- $r = 0; // rowcount
- $c = 0; // colcount
- foreach ($children as $child_pos) {
- $this->debug("in buildVal, got an MD array element: $r, $c");
- $params[$r][] = $this->message[$child_pos]['result'];
- $c++;
- if ($c == $this->message[$pos]['arrayCols']) {
- $c = 0;
- $r++;
- }
- }
- // array
- } elseif ($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array') {
- $this->debug('in buildVal, adding array ' . $this->message[$pos]['name']);
- foreach ($children as $child_pos) {
- $params[] = &$this->message[$child_pos]['result'];
- }
- // apache Map type: java hashtable
- } elseif ($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
- $this->debug('in buildVal, Java Map ' . $this->message[$pos]['name']);
- foreach ($children as $child_pos) {
- $kv = explode("|", $this->message[$child_pos]['children']);
- $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result'];
- }
- // generic compound type
- //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') {
- } else {
- // Apache Vector type: treat as an array
- $this->debug('in buildVal, adding Java Vector or generic compound type ' . $this->message[$pos]['name']);
- if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') {
- $notstruct = 1;
- } else {
- $notstruct = 0;
- }
- //
- foreach ($children as $child_pos) {
- if ($notstruct) {
- $params[] = &$this->message[$child_pos]['result'];
- } else {
- if (isset($params[$this->message[$child_pos]['name']])) {
- // de-serialize repeated element name into an array
- if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) {
- $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
- }
- $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result'];
- } else {
- $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result'];
- }
- }
- }
- }
- if (isset($this->message[$pos]['xattrs'])) {
- $this->debug('in buildVal, handling attributes');
- foreach ($this->message[$pos]['xattrs'] as $n => $v) {
- $params[$n] = $v;
- }
- }
- // handle simpleContent
- if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
- $this->debug('in buildVal, handling simpleContent');
- if (isset($this->message[$pos]['type'])) {
- $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
- } else {
- $parent = $this->message[$pos]['parent'];
- if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
- $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
- } else {
- $params['!'] = $this->message[$pos]['cdata'];
- }
- }
- }
- $ret = is_array($params) ? $params : array();
- $this->debug('in buildVal, return:');
- $this->appendDebug($this->varDump($ret));
- return $ret;
- } else {
- $this->debug('in buildVal, no children, building scalar');
- $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
- if (isset($this->message[$pos]['type'])) {
- $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
- $this->debug("in buildVal, return: $ret");
- return $ret;
- }
- $parent = $this->message[$pos]['parent'];
- if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) {
- $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
- $this->debug("in buildVal, return: $ret");
- return $ret;
- }
- $ret = $this->message[$pos]['cdata'];
- $this->debug("in buildVal, return: $ret");
- return $ret;
- }
- }
-}
-
-
-/**
- * Backward compatibility
- */
-class soap_parser extends nusoap_parser
-{
-}
-
-
-/**
- *
- * [nu]soapclient higher level class for easy usage.
- *
- * usage:
- *
- * // instantiate client with server info
- * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
- *
- * // call method, get results
- * echo $soapclient->call( string methodname [ ,array parameters] );
- *
- * // bye bye client
- * unset($soapclient);
- *
- * @author Dietrich Ayala
- * @author Scott Nichol
- * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $
- * @access public
- */
-class nusoap_client extends nusoap_base
-{
-
- var $username = ''; // Username for HTTP authentication
- var $password = ''; // Password for HTTP authentication
- var $authtype = ''; // Type of HTTP authentication
- var $certRequest = array(); // Certificate for HTTP SSL authentication
- var $requestHeaders = false; // SOAP headers in request (text)
- var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text)
- var $responseHeader = null; // SOAP Header from response (parsed)
- var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text)
- var $endpoint;
- var $forceEndpoint = ''; // overrides WSDL endpoint
- var $proxyhost = '';
- var $proxyport = '';
- var $proxyusername = '';
- var $proxypassword = '';
- var $portName = ''; // port name to use in WSDL
- var $xml_encoding = ''; // character set encoding of incoming (response) messages
- var $http_encoding = false;
- var $timeout = 0; // HTTP connection timeout
- var $response_timeout = 30; // HTTP response timeout
- var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error
- var $persistentConnection = false;
- var $defaultRpcParams = false; // This is no longer used
- var $request = ''; // HTTP request
- var $response = ''; // HTTP response
- var $responseData = ''; // SOAP payload of response
- var $cookies = array(); // Cookies from response or for request
- var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode()
- var $operations = array(); // WSDL operations, empty for WSDL initialization error
- var $curl_options = array(); // User-specified cURL options
- var $bindingType = ''; // WSDL operation binding type
- var $use_curl = false; // whether to always try to use cURL
-
- /*
- * fault related variables
- */
- /**
- * @var fault
- * @access public
- */
- var $fault;
- /**
- * @var faultcode
- * @access public
- */
- var $faultcode;
- /**
- * @var faultstring
- * @access public
- */
- var $faultstring;
- /**
- * @var faultdetail
- * @access public
- */
- var $faultdetail;
-
- /**
- * constructor
- *
- * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object)
- * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL
- * @param string $proxyhost optional
- * @param string $proxyport optional
- * @param string $proxyusername optional
- * @param string $proxypassword optional
- * @param integer $timeout set the connection timeout
- * @param integer $response_timeout set the response timeout
- * @param string $portName optional portName in WSDL document
- * @access public
- */
- function __construct($endpoint, $wsdl = false, $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = '')
- {
- parent::__construct();
- $this->endpoint = $endpoint;
- $this->proxyhost = $proxyhost;
- $this->proxyport = $proxyport;
- $this->proxyusername = $proxyusername;
- $this->proxypassword = $proxypassword;
- $this->timeout = $timeout;
- $this->response_timeout = $response_timeout;
- $this->portName = $portName;
-
- $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
- $this->appendDebug('endpoint=' . $this->varDump($endpoint));
-
- // make values
- if ($wsdl) {
- if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) {
- $this->wsdl = $endpoint;
- $this->endpoint = $this->wsdl->wsdl;
- $this->wsdlFile = $this->endpoint;
- $this->debug('existing wsdl instance created from ' . $this->endpoint);
- $this->checkWSDL();
- } else {
- $this->wsdlFile = $this->endpoint;
- $this->wsdl = null;
- $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
- }
- $this->endpointType = 'wsdl';
- } else {
- $this->debug("instantiate SOAP with endpoint at $endpoint");
- $this->endpointType = 'soap';
- }
- }
-
- /**
- * calls method, returns PHP native type
- *
- * @param string $operation SOAP server URL or path
- * @param mixed $params An array, associative or simple, of the parameters
- * for the method call, or a string that is the XML
- * for the call. For rpc style, this call will
- * wrap the XML in a tag named after the method, as
- * well as the SOAP Envelope and Body. For document
- * style, this will only wrap with the Envelope and Body.
- * IMPORTANT: when using an array with document style,
- * in which case there
- * is really one parameter, the root of the fragment
- * used in the call, which encloses what programmers
- * normally think of parameters. A parameter array
- * *must* include the wrapper.
- * @param string $namespace optional method namespace (WSDL can override)
- * @param string $soapAction optional SOAPAction value (WSDL can override)
- * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
- * @param boolean $rpcParams optional (no longer used)
- * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override)
- * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override)
- * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
- * @access public
- */
- function call($operation, $params = array(), $namespace = 'http://tempuri.org', $soapAction = '', $headers = false, $rpcParams = null, $style = 'rpc', $use = 'encoded')
- {
- $this->operation = $operation;
- $this->fault = false;
- $this->setError('');
- $this->request = '';
- $this->response = '';
- $this->responseData = '';
- $this->faultstring = '';
- $this->faultcode = '';
- $this->opData = array();
-
- $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
- $this->appendDebug('params=' . $this->varDump($params));
- $this->appendDebug('headers=' . $this->varDump($headers));
- if ($headers) {
- $this->requestHeaders = $headers;
- }
- if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
- $this->loadWSDL();
- if ($this->getError()) {
- return false;
- }
- }
- // serialize parameters
- if ($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)) {
- // use WSDL for operation
- $this->opData = $opData;
- $this->debug("found operation");
- $this->appendDebug('opData=' . $this->varDump($opData));
- if (isset($opData['soapAction'])) {
- $soapAction = $opData['soapAction'];
- }
- if (!$this->forceEndpoint) {
- $this->endpoint = $opData['endpoint'];
- } else {
- $this->endpoint = $this->forceEndpoint;
- }
- $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
- $style = $opData['style'];
- $use = $opData['input']['use'];
- // add ns to ns array
- if ($namespace != '' && !isset($this->wsdl->namespaces[$namespace])) {
- $nsPrefix = 'ns' . rand(1000, 9999);
- $this->wsdl->namespaces[$nsPrefix] = $namespace;
- }
- $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
- // serialize payload
- if (is_string($params)) {
- $this->debug("serializing param string for WSDL operation $operation");
- $payload = $params;
- } elseif (is_array($params)) {
- $this->debug("serializing param array for WSDL operation $operation");
- $payload = $this->wsdl->serializeRPCParameters($operation, 'input', $params, $this->bindingType);
- } else {
- $this->debug('params must be array or string');
- $this->setError('params must be array or string');
- return false;
- }
- $usedNamespaces = $this->wsdl->usedNamespaces;
- if (isset($opData['input']['encodingStyle'])) {
- $encodingStyle = $opData['input']['encodingStyle'];
- } else {
- $encodingStyle = '';
- }
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- if ($errstr = $this->wsdl->getError()) {
- $this->debug('got wsdl error: ' . $errstr);
- $this->setError('wsdl error: ' . $errstr);
- return false;
- }
- } elseif ($this->endpointType == 'wsdl') {
- // operation not in WSDL
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- $this->setError('operation ' . $operation . ' not present in WSDL.');
- $this->debug("operation '$operation' not present in WSDL.");
- return false;
- } else {
- // no WSDL
- //$this->namespaces['ns1'] = $namespace;
- $nsPrefix = 'ns' . rand(1000, 9999);
- // serialize
- $payload = '';
- if (is_string($params)) {
- $this->debug("serializing param string for operation $operation");
- $payload = $params;
- } elseif (is_array($params)) {
- $this->debug("serializing param array for operation $operation");
- foreach ($params as $k => $v) {
- $payload .= $this->serialize_val($v, $k, false, false, false, false, $use);
- }
- } else {
- $this->debug('params must be array or string');
- $this->setError('params must be array or string');
- return false;
- }
- $usedNamespaces = array();
- if ($use == 'encoded') {
- $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
- } else {
- $encodingStyle = '';
- }
- }
- // wrap RPC calls with method element
- if ($style == 'rpc') {
- if ($use == 'literal') {
- $this->debug("wrapping RPC request with literal method element");
- if ($namespace) {
- // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace
- $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
- $payload .
- "$nsPrefix:$operation>";
- } else {
- $payload = "<$operation>" . $payload . "$operation>";
- }
- } else {
- $this->debug("wrapping RPC request with encoded method element");
- if ($namespace) {
- $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" .
- $payload .
- "$nsPrefix:$operation>";
- } else {
- $payload = "<$operation>" .
- $payload .
- "$operation>";
- }
- }
- }
- // serialize envelope
- $soapmsg = $this->serializeEnvelope($payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle);
- $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
- $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
- // send
- $return = $this->send($this->getHTTPBody($soapmsg), $soapAction, $this->timeout, $this->response_timeout);
- if ($errstr = $this->getError()) {
- $this->debug('Error: ' . $errstr);
- return false;
- } else {
- $this->return = $return;
- $this->debug('sent message successfully and got a(n) ' . gettype($return));
- $this->appendDebug('return=' . $this->varDump($return));
-
- // fault?
- if (is_array($return) && isset($return['faultcode'])) {
- $this->debug('got fault');
- $this->setError($return['faultcode'] . ': ' . $return['faultstring']);
- $this->fault = true;
- foreach ($return as $k => $v) {
- $this->$k = $v;
- if (is_array($v)) {
- $this->debug("$k = " . json_encode($v));
- } else {
- $this->debug("$k = $v ");
- }
- }
- return $return;
- } elseif ($style == 'document') {
- // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
- // we are only going to return the first part here...sorry about that
- return $return;
- } else {
- // array of return values
- if (is_array($return)) {
- // multiple 'out' parameters, which we return wrapped up
- // in the array
- if (sizeof($return) > 1) {
- return $return;
- }
- // single 'out' parameter (normally the return value)
- $return = array_shift($return);
- $this->debug('return shifted value: ');
- $this->appendDebug($this->varDump($return));
- return $return;
- // nothing returned (ie, echoVoid)
- } else {
- return "";
- }
- }
- }
- }
-
- /**
- * check WSDL passed as an instance or pulled from an endpoint
- *
- * @access private
- */
- function checkWSDL()
- {
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- $this->debug('checkWSDL');
- // catch errors
- if ($errstr = $this->wsdl->getError()) {
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- $this->debug('got wsdl error: ' . $errstr);
- $this->setError('wsdl error: ' . $errstr);
- } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) {
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- $this->bindingType = 'soap';
- $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
- } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) {
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- $this->bindingType = 'soap12';
- $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
- $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
- } else {
- $this->appendDebug($this->wsdl->getDebug());
- $this->wsdl->clearDebug();
- $this->debug('getOperations returned false');
- $this->setError('no operations defined in the WSDL document!');
- }
- }
-
- /**
- * instantiate wsdl object and parse wsdl file
- *
- * @access public
- */
- function loadWSDL()
- {
- $this->debug('instantiating wsdl class with doc: ' . $this->wsdlFile);
- $this->wsdl = new wsdl('', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl);
- $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
- $this->wsdl->fetchWSDL($this->wsdlFile);
- $this->checkWSDL();
- }
-
- /**
- * get available data pertaining to an operation
- *
- * @param string $operation operation name
- * @return array array of data pertaining to the operation
- * @access public
- */
- function getOperationData($operation)
- {
- if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
- $this->loadWSDL();
- if ($this->getError()) {
- return false;
- }
- }
- if (isset($this->operations[$operation])) {
- return $this->operations[$operation];
- }
- $this->debug("No data for operation: $operation");
- }
-
- /**
- * send the SOAP message
- *
- * Note: if the operation has multiple return values
- * the return value of this method will be an array
- * of those values.
- *
- * @param string $msg a SOAPx4 soapmsg object
- * @param string $soapaction SOAPAction value
- * @param integer $timeout set connection timeout in seconds
- * @param integer $response_timeout set response timeout in seconds
- * @return mixed native PHP types.
- * @access private
- */
- function send($msg, $soapaction = '', $timeout = 0, $response_timeout = 30)
- {
- $this->checkCookies();
- // detect transport
- switch (true) {
- // http(s)
- case preg_match('/^http/', $this->endpoint):
- $this->debug('transporting via HTTP');
- if ($this->persistentConnection == true && is_object($this->persistentConnection)) {
- $http =& $this->persistentConnection;
- } else {
- $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
- if ($this->persistentConnection) {
- $http->usePersistentConnection();
- }
- }
- $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
- $http->setSOAPAction($soapaction);
- if ($this->proxyhost && $this->proxyport) {
- $http->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
- }
- if ($this->authtype != '') {
- $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
- }
- if ($this->http_encoding != '') {
- $http->setEncoding($this->http_encoding);
- }
- $this->debug('sending message, length=' . strlen($msg));
- if (preg_match('/^http:/', $this->endpoint)) {
- //if(strpos($this->endpoint,'http:')){
- $this->responseData = $http->send($msg, $timeout, $response_timeout, $this->cookies);
- } elseif (preg_match('/^https/', $this->endpoint)) {
- //} elseif(strpos($this->endpoint,'https:')){
- //if(phpversion() == '4.3.0-dev'){
- //$response = $http->send($msg,$timeout,$response_timeout);
- //$this->request = $http->outgoing_payload;
- //$this->response = $http->incoming_payload;
- //} else
- $this->responseData = $http->sendHTTPS($msg, $timeout, $response_timeout, $this->cookies);
- } else {
- $this->setError('no http/s in endpoint url');
- }
- $this->request = $http->outgoing_payload;
- $this->response = $http->incoming_payload;
- $this->appendDebug($http->getDebug());
- $this->UpdateCookies($http->incoming_cookies);
-
- // save transport object if using persistent connections
- if ($this->persistentConnection) {
- $http->clearDebug();
- if (!is_object($this->persistentConnection)) {
- $this->persistentConnection = $http;
- }
- }
-
- if ($err = $http->getError()) {
- $this->setError('HTTP Error: ' . $err);
- return false;
- } elseif ($this->getError()) {
- return false;
- } else {
- $this->debug('got response, length=' . strlen($this->responseData) . ' type=' . $http->incoming_headers['content-type']);
- return $this->parseResponse($http->incoming_headers, $this->responseData);
- }
- break;
- default:
- $this->setError('no transport found, or selected transport is not yet supported!');
- return false;
- break;
- }
- }
-
- /**
- * processes SOAP message returned from server
- *
- * @param array $headers The HTTP headers
- * @param string $data unprocessed response data from server
- * @return mixed value of the message, decoded into a PHP type
- * @access private
- */
- function parseResponse($headers, $data)
- {
- $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
- $this->appendDebug($this->varDump($headers));
- if (!isset($headers['content-type'])) {
- $this->setError('Response not of type '.$this->contentType.' (no content-type header)');
- return false;
- }
- if (!strstr($headers['content-type'], $this->contentType)) {
- $this->setError('Response not of type '.$this->contentType.': ' . $headers['content-type']);
- return false;
- }
- if (strpos($headers['content-type'], '=')) {
- $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1));
- $this->debug('Got response encoding: ' . $enc);
- if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
- $this->xml_encoding = strtoupper($enc);
- } else {
- $this->xml_encoding = 'US-ASCII';
- }
- } else {
- // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
- $this->xml_encoding = 'ISO-8859-1';
- }
- $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
- $parser = new nusoap_parser($data, $this->xml_encoding, $this->operations, $this->decode_utf8);
- // add parser debug data to our debug
- $this->appendDebug($parser->getDebug());
- // if parse errors
- if ($errstr = $parser->getError()) {
- $this->setError($errstr);
- // destroy the parser object
- unset($parser);
- return false;
- } else {
- // get SOAP headers
- $this->responseHeaders = $parser->getHeaders();
- // get SOAP headers
- $this->responseHeader = $parser->get_soapheader();
- // get decoded message
- $return = $parser->get_soapbody();
- // add document for doclit support
- $this->document = $parser->document;
- // destroy the parser object
- unset($parser);
- // return decode message
- return $return;
- }
- }
-
- /**
- * sets user-specified cURL options
- *
- * @param mixed $option The cURL option (always integer?)
- * @param mixed $value The cURL option value
- * @access public
- */
- function setCurlOption($option, $value)
- {
- $this->debug("setCurlOption option=$option, value=");
- $this->appendDebug($this->varDump($value));
- $this->curl_options[$option] = $value;
- }
-
- /**
- * sets the SOAP endpoint, which can override WSDL
- *
- * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override
- * @access public
- */
- function setEndpoint($endpoint)
- {
- $this->debug("setEndpoint(\"$endpoint\")");
- $this->forceEndpoint = $endpoint;
- }
-
- /**
- * set the SOAP headers
- *
- * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
- * @access public
- */
- function setHeaders($headers)
- {
- $this->debug("setHeaders headers=");
- $this->appendDebug($this->varDump($headers));
- $this->requestHeaders = $headers;
- }
-
- /**
- * get the SOAP response headers (namespace resolution incomplete)
- *
- * @return string
- * @access public
- */
- function getHeaders()
- {
- return $this->responseHeaders;
- }
-
- /**
- * get the SOAP response Header (parsed)
- *
- * @return mixed
- * @access public
- */
- function getHeader()
- {
- return $this->responseHeader;
- }
-
- /**
- * set proxy info here
- *
- * @param string $proxyhost
- * @param string $proxyport
- * @param string $proxyusername
- * @param string $proxypassword
- * @access public
- */
- function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
- {
- $this->proxyhost = $proxyhost;
- $this->proxyport = $proxyport;
- $this->proxyusername = $proxyusername;
- $this->proxypassword = $proxypassword;
- }
-
- /**
- * if authenticating, set user credentials here
- *
- * @param string $username
- * @param string $password
- * @param string $authtype (basic|digest|certificate|ntlm)
- * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
- * @access public
- */
- function setCredentials($username, $password, $authtype = 'basic', $certRequest = array())
- {
- $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
- $this->appendDebug($this->varDump($certRequest));
- $this->username = $username;
- $this->password = $password;
- $this->authtype = $authtype;
- $this->certRequest = $certRequest;
- }
-
- /**
- * use HTTP encoding
- *
- * @param string $enc HTTP encoding
- * @access public
- */
- function setHTTPEncoding($enc = 'gzip, deflate')
- {
- $this->debug("setHTTPEncoding(\"$enc\")");
- $this->http_encoding = $enc;
- }
-
- /**
- * Set whether to try to use cURL connections if possible
- *
- * @param boolean $use Whether to try to use cURL
- * @access public
- */
- function setUseCURL($use)
- {
- $this->debug("setUseCURL($use)");
- $this->use_curl = $use;
- }
-
- /**
- * use HTTP persistent connections if possible
- *
- * @access public
- */
- function useHTTPPersistentConnection()
- {
- $this->debug("useHTTPPersistentConnection");
- $this->persistentConnection = true;
- }
-
- /**
- * gets the default RPC parameter setting.
- * If true, default is that call params are like RPC even for document style.
- * Each call() can override this value.
- *
- * This is no longer used.
- *
- * @return boolean
- * @access public
- * @deprecated
- */
- function getDefaultRpcParams()
- {
- return $this->defaultRpcParams;
- }
-
- /**
- * sets the default RPC parameter setting.
- * If true, default is that call params are like RPC even for document style
- * Each call() can override this value.
- *
- * This is no longer used.
- *
- * @param boolean $rpcParams
- * @access public
- * @deprecated
- */
- function setDefaultRpcParams($rpcParams)
- {
- $this->defaultRpcParams = $rpcParams;
- }
-
- /**
- * dynamically creates an instance of a proxy class,
- * allowing user to directly call methods from wsdl
- *
- * @return object soap_proxy object
- * @access public
- */
- function getProxy()
- {
- $r = rand();
- $evalStr = $this->_getProxyClassCode($r);
- //$this->debug("proxy class: $evalStr");
- if ($this->getError()) {
- $this->debug("Error from _getProxyClassCode, so return null");
- return null;
- }
- // eval the class
- eval($evalStr);
- // instantiate proxy object
- eval("\$proxy = new nusoap_proxy_$r('');");
- // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
- $proxy->endpointType = 'wsdl';
- $proxy->wsdlFile = $this->wsdlFile;
- $proxy->wsdl = $this->wsdl;
- $proxy->operations = $this->operations;
- $proxy->defaultRpcParams = $this->defaultRpcParams;
- // transfer other state
- $proxy->soap_defencoding = $this->soap_defencoding;
- $proxy->username = $this->username;
- $proxy->password = $this->password;
- $proxy->authtype = $this->authtype;
- $proxy->certRequest = $this->certRequest;
- $proxy->requestHeaders = $this->requestHeaders;
- $proxy->endpoint = $this->endpoint;
- $proxy->forceEndpoint = $this->forceEndpoint;
- $proxy->proxyhost = $this->proxyhost;
- $proxy->proxyport = $this->proxyport;
- $proxy->proxyusername = $this->proxyusername;
- $proxy->proxypassword = $this->proxypassword;
- $proxy->http_encoding = $this->http_encoding;
- $proxy->timeout = $this->timeout;
- $proxy->response_timeout = $this->response_timeout;
- $proxy->persistentConnection = &$this->persistentConnection;
- $proxy->decode_utf8 = $this->decode_utf8;
- $proxy->curl_options = $this->curl_options;
- $proxy->bindingType = $this->bindingType;
- $proxy->use_curl = $this->use_curl;
- return $proxy;
- }
-
- /**
- * dynamically creates proxy class code
- *
- * @return string PHP/NuSOAP code for the proxy class
- * @access private
- */
- function _getProxyClassCode($r)
- {
- $this->debug("in getProxy endpointType=$this->endpointType");
- $this->appendDebug("wsdl=" . $this->varDump($this->wsdl));
- if ($this->endpointType != 'wsdl') {
- $evalStr = 'A proxy can only be created for a WSDL client';
- $this->setError($evalStr);
- $evalStr = "echo \"$evalStr\";";
- return $evalStr;
- }
- if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) {
- $this->loadWSDL();
- if ($this->getError()) {
- return "echo \"" . $this->getError() . "\";";
- }
- }
- $evalStr = '';
- foreach ($this->operations as $operation => $opData) {
- if ($operation != '') {
- // create param string and param comment string
- if (sizeof($opData['input']['parts']) > 0) {
- $paramStr = '';
- $paramArrayStr = '';
- $paramCommentStr = '';
- foreach ($opData['input']['parts'] as $name => $type) {
- $paramStr .= "\$$name, ";
- $paramArrayStr .= "'$name' => \$$name, ";
- $paramCommentStr .= "$type \$$name, ";
- }
- $paramStr = substr($paramStr, 0, strlen($paramStr) - 2);
- $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr) - 2);
- $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr) - 2);
- } else {
- $paramStr = '';
- $paramArrayStr = '';
- $paramCommentStr = 'void';
- }
- $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
- $evalStr .= "// $paramCommentStr
- function " . str_replace('.', '__', $operation) . "($paramStr) {
- \$params = array($paramArrayStr);
- return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . (isset($opData['soapAction']) ? $opData['soapAction'] : '') . "');
- }
- ";
- unset($paramStr);
- unset($paramCommentStr);
- }
- }
- $evalStr = 'class nusoap_proxy_' . $r . ' extends nusoap_client {
- ' . $evalStr . '
-}';
- return $evalStr;
- }
-
- /**
- * dynamically creates proxy class code
- *
- * @return string PHP/NuSOAP code for the proxy class
- * @access public
- */
- function getProxyClassCode()
- {
- $r = rand();
- return $this->_getProxyClassCode($r);
- }
-
- /**
- * gets the HTTP body for the current request.
- *
- * @param string $soapmsg The SOAP payload
- * @return string The HTTP body, which includes the SOAP payload
- * @access private
- */
- function getHTTPBody($soapmsg)
- {
- return $soapmsg;
- }
-
- /**
- * gets the HTTP content type for the current request.
- *
- * Note: getHTTPBody must be called before this.
- *
- * @return string the HTTP content type for the current request.
- * @access private
- */
- function getHTTPContentType()
- {
- return $this->contentType;
- }
-
- /**
- * allows you to change the HTTP ContentType of the request.
- *
- * @param string $contentTypeNew
- * @return void
- */
- function setHTTPContentType($contentTypeNew = "text/xml"){
- $this->contentType = $contentTypeNew;
- }
-
- /**
- * gets the HTTP content type charset for the current request.
- * returns false for non-text content types.
- *
- * Note: getHTTPBody must be called before this.
- *
- * @return string the HTTP content type charset for the current request.
- * @access private
- */
- function getHTTPContentTypeCharset()
- {
- return $this->soap_defencoding;
- }
-
- /*
- * whether or not parser should decode utf8 element content
- *
- * @return always returns true
- * @access public
- */
- function decodeUTF8($bool)
- {
- $this->decode_utf8 = $bool;
- return true;
- }
-
- /**
- * adds a new Cookie into $this->cookies array
- *
- * @param string $name Cookie Name
- * @param string $value Cookie Value
- * @return boolean if cookie-set was successful returns true, else false
- * @access public
- */
- function setCookie($name, $value)
- {
- if (strlen($name) == 0) {
- return false;
- }
- $this->cookies[] = array('name' => $name, 'value' => $value);
- return true;
- }
-
- /**
- * gets all Cookies
- *
- * @return array with all internal cookies
- * @access public
- */
- function getCookies()
- {
- return $this->cookies;
- }
-
- /**
- * checks all Cookies and delete those which are expired
- *
- * @return boolean always return true
- * @access private
- */
- function checkCookies()
- {
- if (sizeof($this->cookies) == 0) {
- return true;
- }
- $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies');
- $curr_cookies = $this->cookies;
- $this->cookies = array();
- foreach ($curr_cookies as $cookie) {
- if (!is_array($cookie)) {
- $this->debug('Remove cookie that is not an array');
- continue;
- }
- if ((isset($cookie['expires'])) && (!empty($cookie['expires']))) {
- if (strtotime($cookie['expires']) > time()) {
- $this->cookies[] = $cookie;
- } else {
- $this->debug('Remove expired cookie ' . $cookie['name']);
- }
- } else {
- $this->cookies[] = $cookie;
- }
- }
- $this->debug('checkCookie: ' . sizeof($this->cookies) . ' cookies left in array');
- return true;
- }
-
- /**
- * updates the current cookies with a new set
- *
- * @param array $cookies new cookies with which to update current ones
- * @return boolean always return true
- * @access private
- */
- function UpdateCookies($cookies)
- {
- if (sizeof($this->cookies) == 0) {
- // no existing cookies: take whatever is new
- if (sizeof($cookies) > 0) {
- $this->debug('Setting new cookie(s)');
- $this->cookies = $cookies;
- }
- return true;
- }
- if (sizeof($cookies) == 0) {
- // no new cookies: keep what we've got
- return true;
- }
- // merge
- foreach ($cookies as $newCookie) {
- if (!is_array($newCookie)) {
- continue;
- }
- if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
- continue;
- }
- $newName = $newCookie['name'];
-
- $found = false;
- for ($i = 0; $i < count($this->cookies); $i++) {
- $cookie = $this->cookies[$i];
- if (!is_array($cookie)) {
- continue;
- }
- if (!isset($cookie['name'])) {
- continue;
- }
- if ($newName != $cookie['name']) {
- continue;
- }
- $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
- $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
- if ($newDomain != $domain) {
- continue;
- }
- $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
- $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
- if ($newPath != $path) {
- continue;
- }
- $this->cookies[$i] = $newCookie;
- $found = true;
- $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
- break;
- }
- if (!$found) {
- $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
- $this->cookies[] = $newCookie;
- }
- }
- return true;
- }
-}
-
-
-if (!extension_loaded('soap')) {
- /**
- * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
- */
- class soapclient extends nusoap_client
- {
- }
-}
-
-/**
- * caches instances of the wsdl class
- *
- * @author Scott Nichol
- * @author Ingo Fischer
- * @version $Id: class.wsdlcache.php,v 1.7 2007/04/17 16:34:03 snichol Exp $
- * @access public
- */
-class nusoap_wsdlcache {
- /**
- * @var resource
- * @access private
- */
- var $fplock;
- /**
- * @var integer
- * @access private
- */
- var $cache_lifetime;
- /**
- * @var string
- * @access private
- */
- var $cache_dir;
- /**
- * @var string
- * @access public
- */
- var $debug_str = '';
-
- /**
- * constructor
- *
- * @param string $cache_dir directory for cache-files
- * @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited
- * @access public
- */
- function __construct($cache_dir='.', $cache_lifetime=0) {
- $this->fplock = array();
- $this->cache_dir = $cache_dir != '' ? $cache_dir : '.';
- $this->cache_lifetime = $cache_lifetime;
- }
-
- /**
- * creates the filename used to cache a wsdl instance
- *
- * @param string $wsdl The URL of the wsdl instance
- * @return string The filename used to cache the instance
- * @access private
- */
- function createFilename($wsdl) {
- return $this->cache_dir.'/wsdlcache-' . md5($wsdl);
- }
-
- /**
- * adds debug data to the class level debug string
- *
- * @param string $string debug data
- * @access private
- */
- function debug($string){
- $this->debug_str .= get_class($this).": $string\n";
- }
-
- /**
- * gets a wsdl instance from the cache
- *
- * @param string $wsdl The URL of the wsdl instance
- * @return object wsdl The cached wsdl instance, null if the instance is not in the cache
- * @access public
- */
- function get($wsdl) {
- $filename = $this->createFilename($wsdl);
- if ($this->obtainMutex($filename, "r")) {
- // check for expired WSDL that must be removed from the cache
- if ($this->cache_lifetime > 0) {
- if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) {
- unlink($filename);
- $this->debug("Expired $wsdl ($filename) from cache");
- $this->releaseMutex($filename);
- return null;
- }
- }
- // see what there is to return
- if (!file_exists($filename)) {
- $this->debug("$wsdl ($filename) not in cache (1)");
- $this->releaseMutex($filename);
- return null;
- }
- $fp = @fopen($filename, "r");
- if ($fp) {
- $s = implode("", @file($filename));
- fclose($fp);
- $this->debug("Got $wsdl ($filename) from cache");
- } else {
- $s = null;
- $this->debug("$wsdl ($filename) not in cache (2)");
- }
- $this->releaseMutex($filename);
- return (!is_null($s)) ? unserialize($s) : null;
- } else {
- $this->debug("Unable to obtain mutex for $filename in get");
- }
- return null;
- }
-
- /**
- * obtains the local mutex
- *
- * @param string $filename The Filename of the Cache to lock
- * @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode
- * @return boolean Lock successfully obtained ?!
- * @access private
- */
- function obtainMutex($filename, $mode) {
- if (isset($this->fplock[md5($filename)])) {
- $this->debug("Lock for $filename already exists");
- return false;
- }
- $this->fplock[md5($filename)] = fopen($filename.".lock", "w");
- if ($mode == "r") {
- return flock($this->fplock[md5($filename)], LOCK_SH);
- } else {
- return flock($this->fplock[md5($filename)], LOCK_EX);
- }
- }
-
- /**
- * adds a wsdl instance to the cache
- *
- * @param object wsdl $wsdl_instance The wsdl instance to add
- * @return boolean WSDL successfully cached
- * @access public
- */
- function put($wsdl_instance) {
- $filename = $this->createFilename($wsdl_instance->wsdl);
- $s = serialize($wsdl_instance);
- if ($this->obtainMutex($filename, "w")) {
- $fp = fopen($filename, "w");
- if (! $fp) {
- $this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache");
- $this->releaseMutex($filename);
- return false;
- }
- fputs($fp, $s);
- fclose($fp);
- $this->debug("Put $wsdl_instance->wsdl ($filename) in cache");
- $this->releaseMutex($filename);
- return true;
- } else {
- $this->debug("Unable to obtain mutex for $filename in put");
- }
- return false;
- }
-
- /**
- * releases the local mutex
- *
- * @param string $filename The Filename of the Cache to lock
- * @return boolean Lock successfully released
- * @access private
- */
- function releaseMutex($filename) {
- $ret = flock($this->fplock[md5($filename)], LOCK_UN);
- fclose($this->fplock[md5($filename)]);
- unset($this->fplock[md5($filename)]);
- if (! $ret) {
- $this->debug("Not able to release lock for $filename");
- }
- return $ret;
- }
-
- /**
- * removes a wsdl instance from the cache
- *
- * @param string $wsdl The URL of the wsdl instance
- * @return boolean Whether there was an instance to remove
- * @access public
- */
- function remove($wsdl) {
- $filename = $this->createFilename($wsdl);
- if (!file_exists($filename)) {
- $this->debug("$wsdl ($filename) not in cache to be removed");
- return false;
- }
- // ignore errors obtaining mutex
- $this->obtainMutex($filename, "w");
- $ret = unlink($filename);
- $this->debug("Removed ($ret) $wsdl ($filename) from cache");
- $this->releaseMutex($filename);
- return $ret;
- }
-}
-
-/**
- * For backward compatibility
- */
-class wsdlcache extends nusoap_wsdlcache {
-}
diff --git a/application/plugins/stop_manager/media/pgsql_stop_manager.sql b/application/plugins/stop_manager/media/pgsql_stop_manager.sql
index 4e997364c..9ffe02095 100644
--- a/application/plugins/stop_manager/media/pgsql_stop_manager.sql
+++ b/application/plugins/stop_manager/media/pgsql_stop_manager.sql
@@ -4,7 +4,7 @@
-- Table structure for table `plugin_stop_manager`
--
-CREATE TABLE "plugin_stop_manager" (
+CREATE TABLE IF NOT EXISTS "plugin_stop_manager" (
"id_stop_manager" serial PRIMARY KEY,
"destination_number" varchar(20) NOT NULL,
"stop_type" varchar(50) NOT NULL,
diff --git a/application/plugins/stop_manager/media/sqlite_stop_manager.sql b/application/plugins/stop_manager/media/sqlite_stop_manager.sql
index bfb6712c1..51fed3226 100644
--- a/application/plugins/stop_manager/media/sqlite_stop_manager.sql
+++ b/application/plugins/stop_manager/media/sqlite_stop_manager.sql
@@ -4,7 +4,7 @@
-- Table structure for table `plugin_stop_manager`
--
-CREATE TABLE "plugin_stop_manager" (
+CREATE TABLE IF NOT EXISTS "plugin_stop_manager" (
"id_stop_manager" INTEGER PRIMARY KEY AUTOINCREMENT,
"destination_number" VARCHAR(20) NOT NULL,
"stop_type" VARCHAR(50) NOT NULL,
diff --git a/application/plugins/whitelist_number/media/pgsql_whitelist_number.sql b/application/plugins/whitelist_number/media/pgsql_whitelist_number.sql
index 0d7824309..04b89c78b 100644
--- a/application/plugins/whitelist_number/media/pgsql_whitelist_number.sql
+++ b/application/plugins/whitelist_number/media/pgsql_whitelist_number.sql
@@ -1,4 +1,4 @@
-CREATE TABLE "plugin_whitelist_number" (
+CREATE TABLE IF NOT EXISTS "plugin_whitelist_number" (
"id_whitelist" serial PRIMARY KEY,
"match" varchar(200) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/plugins/whitelist_number/media/sqlite_whitelist_number.sql b/application/plugins/whitelist_number/media/sqlite_whitelist_number.sql
index 304d6eee4..95a63becf 100644
--- a/application/plugins/whitelist_number/media/sqlite_whitelist_number.sql
+++ b/application/plugins/whitelist_number/media/sqlite_whitelist_number.sql
@@ -1,4 +1,4 @@
-CREATE TABLE "plugin_whitelist_number" (
+CREATE TABLE IF NOT EXISTS "plugin_whitelist_number" (
"id_whitelist" INTEGER PRIMARY KEY AUTOINCREMENT,
"match" VARCHAR(200) NOT NULL
-);
\ No newline at end of file
+);
diff --git a/application/sql/mysql/kalkun.sql b/application/sql/mysql/kalkun.sql
index db655a7d9..666762d48 100644
--- a/application/sql/mysql/kalkun.sql
+++ b/application/sql/mysql/kalkun.sql
@@ -157,9 +157,8 @@ CREATE TABLE IF NOT EXISTS `user_settings` (
-- Dumping data for table `user_settings`
--
-INSERT INTO `user_settings` (`id_user`, `theme`, `signature`, `permanent_delete`, `paging`, `bg_image`, `delivery_report`, `language`, `conversation_sort`) VALUES
-(1, 'green', 'false;--\nPut your signature here', 'false', 20, 'true;background.jpg', 'default' , 'english', 'asc');
-
+INSERT INTO `user_settings` VALUES (1, 'green', 'false;--
+Put your signature here', 'false', 20, 'true;background.jpg', 'default', 'english', 'asc', 'US');
-- --------------------------------------------------------
diff --git a/application/sql/pgsql/kalkun.sql b/application/sql/pgsql/kalkun.sql
index cec231a75..9d7238cd3 100644
--- a/application/sql/pgsql/kalkun.sql
+++ b/application/sql/pgsql/kalkun.sql
@@ -30,8 +30,8 @@ CREATE TABLE "user_settings" (
);
INSERT INTO "user" VALUES(1, 'kalkun', 'Kalkun SMS', '$2y$10$sIXe0JiaTIOsC7OOnox5t.deuJwZoawd5QKpQlSNfywziTDHpmmyy', '123456789', 'admin');
-INSERT INTO "user_settings" VALUES (1, 'green', 'false;Put your signature here', 'false', 20, 'true;background.jpg', 'default', 'english', 'asc');
-
+INSERT INTO "user_settings" VALUES (1, 'green', 'false;--
+Put your signature here', 'false', 20, 'true;background.jpg', 'default', 'english', 'asc', 'US');
CREATE TABLE "user_outbox" (
"id_outbox" integer PRIMARY KEY,
diff --git a/application/sql/sqlite/kalkun.sql b/application/sql/sqlite/kalkun.sql
index 5468d015b..2ebafd411 100644
--- a/application/sql/sqlite/kalkun.sql
+++ b/application/sql/sqlite/kalkun.sql
@@ -26,7 +26,8 @@ CREATE TABLE "user_settings" (
CHECK ("conversation_sort" IN ('asc','desc'))
);
-INSERT INTO "user_settings" VALUES (1, 'green', 'false;--\nPut your signature here', 'false', 20, 'true;background.jpg', 'default', 'english', 'asc');
+INSERT INTO "user_settings" VALUES (1, 'green', 'false;--
+Put your signature here', 'false', 20, 'true;background.jpg', 'default', 'english', 'asc', 'US');
CREATE TABLE "user_outbox" (
"id_outbox" INTEGER PRIMARY KEY NOT NULL,
diff --git a/application/views/js_init/message/js_compose.php b/application/views/js_init/message/js_compose.php
index 8e989ce5d..51f3b0d81 100644
--- a/application/views/js_init/message/js_compose.php
+++ b/application/views/js_init/message/js_compose.php
@@ -201,7 +201,7 @@ function onTagInputKeydown(e) {
manualvalue: {
required: "#sendoption3:checked",
remote: {
- url: "",
+ url: "",
type: "get",
data: {
phone: function() {
diff --git a/application/views/main/dashboard/home.php b/application/views/main/dashboard/home.php
index 82247b867..56449ba96 100644
--- a/application/views/main/dashboard/home.php
+++ b/application/views/main/dashboard/home.php
@@ -31,7 +31,7 @@
:
- Kalkun_model->get_gammu_info('gammu_version')->row('Client')), ENT_QUOTES); ?>
+ Kalkun_model->get_gammu_info('gammu_version')->row('Client') !== NULL ? $this->Kalkun_model->get_gammu_info('gammu_version')->row('Client') : ''), ENT_QUOTES); ?>
@@ -41,7 +41,7 @@
:
- Kalkun_model->get_gammu_info('phone_imei')->row('IMEI')), ENT_QUOTES); ?>
+ Kalkun_model->get_gammu_info('phone_imei')->row('IMEI') !== NULL ? $this->Kalkun_model->get_gammu_info('phone_imei')->row('IMEI') : ''), ENT_QUOTES); ?>
diff --git a/application/views/main/dashboard/statistic.php b/application/views/main/dashboard/statistic.php
index 77a249759..6cadf16aa 100644
--- a/application/views/main/dashboard/statistic.php
+++ b/application/views/main/dashboard/statistic.php
@@ -1,7 +1,7 @@
load->view('js_init/js_dashboard');?>
-
+
diff --git a/application/views/main/forgot_password.php b/application/views/main/forgot_password.php
index b7c0e5041..2b9567341 100644
--- a/application/views/main/forgot_password.php
+++ b/application/views/main/forgot_password.php
@@ -11,7 +11,7 @@
config->item('img_path').'icon.ico', 'shortcut icon', 'image/ico');?>
config->item('css_path').'base.css');?>
-
+
-
+
lang->get_jquery_datepicker_regional(APPPATH.'../media/js/jquery-ui/i18n');
-$jquery_ui_i18n = FCPATH."media/js/jquery-ui/i18n/datepicker-${jquery_datepicker_regional}.js";
+$jquery_ui_i18n = FCPATH."media/js/jquery-ui/i18n/datepicker-{$jquery_datepicker_regional}.js";
if ($jquery_datepicker_regional !== '' && file_exists($jquery_ui_i18n)):
?>
diff --git a/application/views/main/install/layout.php b/application/views/main/install/layout.php
index ee51275eb..9d9386a5a 100644
--- a/application/views/main/install/layout.php
+++ b/application/views/main/install/layout.php
@@ -7,7 +7,7 @@
-
+
+
+