diff --git a/.travis.yml b/.travis.yml index 96f02d83..187d7f28 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,22 +15,27 @@ env: - PHPSQLDIR=/REPO/msphpsql-dev - TEST_PHP_SQL_SERVER=sql - SQLSRV_DBNAME=msphpsql_sqlsrv - - PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv + - PDOSQLSRV_DBNAME=msphpsql_pdosqlsrv before_install: - docker pull microsoft/mssql-server-linux install: + - docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password123' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux - docker build --build-arg PHPSQLDIR=$PHPSQLDIR -t msphpsql-dev -f Dockerfile-msphpsql . - - docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=Password12@' -p 1433:1433 --name=$TEST_PHP_SQL_SERVER -d microsoft/mssql-server-linux +before_script: + - sleep 30 + script: - - docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --link $TEST_PHP_SQL_SERVER --name=client msphpsql-dev - - docker ps -a - - docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME - - docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME - - docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt - - docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt + - travis_retry docker run -e TRAVIS_JOB_ID -t -d -w $PHPSQLDIR --name=client --link $TEST_PHP_SQL_SERVER msphpsql-dev + - docker ps -a + - docker stats + - docker logs client + - travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $SQLSRV_DBNAME + - travis_retry docker exec client python ./test/functional/setup/setup_dbs.py -dbname $PDOSQLSRV_DBNAME + - travis_retry docker exec client php ./source/pdo_sqlsrv/run-tests.php ./test/functional/pdo_sqlsrv/*.phpt + - travis_retry docker exec client php ./source/sqlsrv/run-tests.php ./test/functional/sqlsrv/*.phpt - docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' - docker exec client bash -c 'for f in ./test/functional/sqlsrv/*.out; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' - docker exec client bash -c 'for f in ./test/functional/pdo_sqlsrv/*.diff; do ls $f 2>/dev/null; cat $f 2>/dev/null; done || true' diff --git a/Dockerfile-msphpsql b/Dockerfile-msphpsql index 81ff073f..6cff1116 100644 --- a/Dockerfile-msphpsql +++ b/Dockerfile-msphpsql @@ -4,29 +4,29 @@ FROM ubuntu:16.04 # Update Ubuntu Software repository RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && \ - apt-get -y install \ - apt-transport-https \ - apt-utils \ - autoconf \ - curl \ - g++ \ - gcc \ - git \ - lcov \ - libxml2-dev \ - locales \ - make \ - php7.0 \ - php7.0-dev \ - python-pip \ - re2c \ - unixodbc-dev \ - unzip && apt-get clean - + apt-get -y install \ + apt-transport-https \ + apt-utils \ + autoconf \ + curl \ + g++ \ + gcc \ + git \ + lcov \ + libxml2-dev \ + locales \ + make \ + php7.0 \ + php7.0-dev \ + python-pip \ + re2c \ + unixodbc-dev \ + unzip && apt-get clean + ARG PHPSQLDIR=/REPO/msphpsql-dev ENV TEST_PHP_SQL_SERVER sql ENV TEST_PHP_SQL_UID sa -ENV TEST_PHP_SQL_PWD Password12@ +ENV TEST_PHP_SQL_PWD Password123 # set locale to utf-8 RUN locale-gen en_US.UTF-8 @@ -36,10 +36,7 @@ ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' LC_ALL='en_US.UTF-8' RUN curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - RUN curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list -#RUN echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/mssql-ubuntu-xenial-release/ xenial main" > /etc/apt/sources.list.d/mssqlpreview.list -#RUN apt-key adv --keyserver apt-mo.trafficmanager.net --recv-keys 417A0893 RUN export DEBIAN_FRONTEND=noninteractive && apt-get update && ACCEPT_EULA=Y apt-get install -y msodbcsql mssql-tools - ENV PATH="/opt/mssql-tools/bin:${PATH}" #install coveralls @@ -47,11 +44,9 @@ RUN pip install --upgrade pip && pip install cpp-coveralls #Either Install git / download zip (One can see other strategies : https://ryanfb.github.io/etc/2015/07/29/git_strategies_for_docker.html ) #One option is to get source from zip file of repository. - #another option is to copy source to build directory on image RUN mkdir -p $PHPSQLDIR COPY . $PHPSQLDIR - WORKDIR $PHPSQLDIR/source/ RUN chmod +x ./packagize.sh @@ -79,6 +74,9 @@ RUN sed -i -e 's/TARGET_DATABASE/msphpsql_sqlsrv/g' MsSetup.inc RUN sed -i -e 's/TARGET_USERNAME/'"$TEST_PHP_SQL_UID"'/g' MsSetup.inc RUN sed -i -e 's/TARGET_PASSWORD/'"$TEST_PHP_SQL_PWD"'/g' MsSetup.inc -ENV REPORT_EXIT_STATUS 1 -ENV TEST_PHP_EXECUTABLE /usr/bin/php +WORKDIR $PHPSQLDIR +RUN chmod +x ./entrypoint.sh +CMD /bin/bash ./entrypoint.sh +ENV REPORT_EXIT_STATUS 1 +ENV TEST_PHP_EXECUTABLE /usr/bin/php \ No newline at end of file diff --git a/README.md b/README.md index c78c480b..78f2cb43 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Thank you for taking time to take our February survey. Let us know how we are do * [**Ubuntu + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/ubuntu) * [**RedHat + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/rhel) +* [**SUSE + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/sles) * [**Windows + SQL Server + PHP 7**](https://www.microsoft.com/en-us/sql-server/developer-get-started/php/windows) * [**Docker**](https://hub.docker.com/r/lbosqmsft/mssql-php-msphpsql/) @@ -42,27 +43,16 @@ Thank you for taking time to take our February survey. Let us know how we are do ## Build (Windows) -Note: if you prefer, you can use the pre-compiled binary found [HERE](https://github.com/Azure/msphpsql/releases) +Note: if you prefer, you can use the pre-compiled binary found [HERE](https://github.com/Microsoft/msphpsql/releases) #### Prerequisites -You must first be able to build PHP 7 without including these extensions. For help with doing this, see the [official PHP website][phpbuild] for building your own PHP on Windows. +You must first be able to build PHP 7* without including these extensions. For help with doing this, see the [official PHP website][phpbuild] for building your own PHP in Windows. #### Compile the drivers -1. Copy the sqlsrv and/or pdo_sqlsrv source code directory from this repository into the ext subdirectory. - -2. Run `buildconf.bat` to rebuild the configure.js script to include the driver. - -3. Run `configure.bat --with-odbcver=0x0380 and the desired driver options (as below) [plus other options such as --disable-zts for the Non Thread Safe build]` to generate the makefile. You can run `configure.bat --help` to see what other options are available. - * For SQLSRV use: `--enable-sqlsrv=shared` - * For PDO_SQLSRV use: `--enable-pdo=shared --with-pdo-sqlsrv=shared` - -4. Run `nmake`. It is suggested that you run the entire build. If you wish to do so, run `nmake clean` first. - -5. To install the resulting build, run `nmake install` or just copy php_sqlsrv.dll and/or php_pdo_sqlsrv.dll to your PHP extension directory. - -This software has been compiled and tested under PHP 7.0.8 using the Visual C++ 2015 compiler. +The Microsoft Drivers for PHP for SQL Server have been compiled and tested with PHP 7.0.* and 7.1.* using Visual C++ 2015 as well as PHP 7.2.0 beta using Visual C++ 2017 v15.0. +For details, please read the documentation and/or take a look at the sample [build scripts](https://github.com/Microsoft/msphpsql/tree/dev/buildscripts#windows). ## Install (Windows) @@ -75,155 +65,215 @@ This software has been compiled and tested under PHP 7.0.8 using the Visual C++ 1. Make sure that the driver is in your PHP extension directory (you can simply copy it there if you did not use nmake install). -2. Enable it within your PHP installation's php.ini: `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll`. If necessary, specify the extension directory using extension_dir, for example: `extension_dir = "C:\PHP\ext"` +2. Enable it within your PHP installation's php.ini: `extension=php_sqlsrv.dll` and/or `extension=php_pdo_sqlsrv.dll`. If necessary, specify the extension directory using extension_dir, for example: `extension_dir = "C:\PHP\ext"`. Note that the precompiled binaries have different names -- substitute accordingly in php.ini. 3. Restart the Web server. ## Install (UNIX) -The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, apache, and Microsoft PHP drivers on Ubuntu 15, 16, RedHat 7 and Mac OS X. To see how to get PHP SQLSRV drivers running on Debian, please visit [Wiki](https://github.com/Microsoft/msphpsql/wiki/Dockerfile-for-getting-pdo_sqlsrv-for-PHP-7.0-on-Debian-in-3-ways). Note that Debian is not officially supported and this instruction hasn't been tested in our test lab. +The following instructions assume a clean environment and show how to install PHP 7.x, Microsoft ODBC driver, Apache, and Microsoft PHP drivers on Ubuntu 15, 16, RedHat 7, Debian 8, SUSE 12, and macOS. ### Step 1: Install PHP7+ #### PHP 7.0 -**Ubuntu 15.04, Ubuntu 15.10** +**Ubuntu 15.10** - sudo su - sh -c 'echo "deb http://packages.dotdeb.org jessie all \ndeb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list' - apt-get update - apt-get install php7.0 php7.0-fpm php-pear php7.0-dev mcrypt php7.0-mcrypt php-mbstring php7.0-xml re2c gcc g++ + sudo su + sh -c 'echo "deb http://packages.dotdeb.org jessie all \ndeb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list' + apt-get update + apt-get install php7.0 php7.0-fpm php-pear php7.0-dev mcrypt php7.0-mcrypt php-mbstring php7.0-xml - **Ubuntu 16.04** - sudo su - apt-get update - apt-get -y install php7.0 mcrypt php7.0-mcrypt php-mbstring php-pear php7.0-dev php7.0-xml re2c gcc g++ + sudo su + apt-get update + apt-get -y install php7.0 mcrypt php7.0-mcrypt php-mbstring php-pear php7.0-dev php7.0-xml - **RedHat 7** - sudo su - wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm - rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm - subscription-manager repos --enable=rhel-7-server-optional-rpms - yum-config-manager --enable remi-php70 - yum update - yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc + sudo su + wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm + rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm + subscription-manager repos --enable=rhel-7-server-optional-rpms + yum-config-manager --enable remi-php70 + yum update + yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc -**Mac OS X** +**Debian 8** - /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - brew tap - brew tap homebrew/dupes - brew tap homebrew/versions - brew tap homebrew/homebrew-php - brew install php70 --with-pear --with-httpd24 --with-cgi - echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile - echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile - source ~/.bash_profile + sudo su + apt-get install curl apt-transport-https + curl https://www.dotdeb.org/dotdeb.gpg | apt-key add - + echo "deb http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list + echo "deb-src http://packages.dotdeb.org jessie all" >> /etc/apt/sources.list + apt-get update + apt-get install -y php7.0 php-pear php7.0-dev php7.0-xml + +**SUSE 12** + + sudo su + zypper refresh + zypper install -y php7 php7-pear php7-devel + +**macOS** + + /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + brew tap + brew tap homebrew/dupes + brew tap homebrew/versions + brew tap homebrew/homebrew-php + brew install php70 --with-pear --with-httpd24 --with-cgi + echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile + echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile + source ~/.bash_profile #### PHP 7.1 +Note that there are no PHP 7.1 packages available for Ubuntu 15.10. **Ubuntu 16.04** - sudo su - add-apt-repository ppa:ondrej/php - apt-get update - apt-get -y install php7.1 mcrypt php7.1-mcrypt php-mbstring php-pear php7.1-dev php7.1-xml + sudo su + add-apt-repository ppa:ondrej/php + apt-get update + apt-get -y install php7.1 mcrypt php7.1-mcrypt php-mbstring php-pear php7.1-dev php7.1-xml **RedHat 7** - - sudo su - wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm - wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm - rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm - subscription-manager repos --enable=rhel-7-server-optional-rpms - yum-config-manager --enable remi-php71 - yum update - yum install php php-pdo php-xml php-pear php-devel - -**Mac OS X** - /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" - brew tap - brew tap homebrew/dupes - brew tap homebrew/versions - brew tap homebrew/homebrew-php - brew install php71 --with-pear --with-httpd24 --with-cgi - echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile - echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile - source ~/.bash_profile + sudo su + wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + wget http://rpms.remirepo.net/enterprise/remi-release-7.rpm + rpm -Uvh remi-release-7.rpm epel-release-latest-7.noarch.rpm + subscription-manager repos --enable=rhel-7-server-optional-rpms + yum-config-manager --enable remi-php71 + yum update + yum install php php-pdo php-xml php-pear php-devel re2c gcc-c++ gcc + +**Debian 8** + + sudo su + apt-get install curl apt-transport-https + wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg + echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list + apt-get update + apt-get install -y php7.1 php-pear php7.1-dev php7.1-xml + +**SUSE 12** + + sudo su + zypper -n ar -f http://download.opensuse.org/repositories/devel:/languages:/php/openSUSE_Leap_42.3/ devel:languages:php + zypper --gpg-auto-import-keys refresh + zypper -n install php7 php7-pear php7-devel + +**macOS** + + /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + brew tap + brew tap homebrew/dupes + brew tap homebrew/versions + brew tap homebrew/homebrew-php + brew install php71 --with-pear --with-httpd24 --with-cgi + echo 'export PATH="/usr/local/sbin:$PATH"' >> ~/.bash_profile + echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile + source ~/.bash_profile ### Step 2: Install Prerequisites - **Ubuntu 15.10** - sudo su - curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-release.list - exit - sudo apt-get update - sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools - sudo apt-get install unixodbc-dev - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc + sudo su + curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - + curl https://packages.microsoft.com/config/ubuntu/15.10/prod.list > /etc/apt/sources.list.d/mssql-release.list + exit + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools + sudo apt-get install unixodbc-dev + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc - **Ubuntu 16.04** - sudo su - curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - - curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list - exit - sudo apt-get update - sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools - sudo apt-get install unixodbc-dev - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc + sudo su + curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - + curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/mssql-release.list + exit + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install msodbcsql mssql-tools + sudo apt-get install unixodbc-dev + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc **RedHat 7** - sudo su - curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo - exit - sudo yum update - sudo yum remove unixODBC-utf16-devel #to avoid conflicts - sudo ACCEPT_EULA=Y yum install msodbcsql mssql-tools - sudo yum install unixODBC-devel - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc - -**Mac OS X** + sudo su + curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo + exit + sudo yum update + sudo yum remove unixODBC-utf16-devel #to avoid conflicts + sudo ACCEPT_EULA=Y yum install msodbcsql mssql-tools + sudo yum install unixODBC-devel + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc - brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-mssql-release - brew update - brew install msodbcsql - brew install mssql-tools - brew install autoconf +**Debian 8** -*Note: You need to make sure you install PHP 7+ before you proceed to step 3. The Microsoft PHP Drivers for SQL Server will only work for PHP 7+. + sudo su + curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - + curl https://packages.microsoft.com/config/debian/8/prod.list > /etc/apt/sources.list.d/mssql-release.list + apt-get install -y locales + echo "en_US.UTF-8 UTF-8" > /etc/locale.gen + locale-gen + exit + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install msodbcsql + sudo apt-get install unixodbc-dev + +**SUSE 12** + + sudo su + zypper ar https://packages.microsoft.com/config/sles/12/prod.repo + sudo zypper --gpg-auto-import-keys refresh + exit + sudo ACCEPT_EULA=Y zypper install msodbcsql + sudo ACCEPT_EULA=Y zypper install mssql-tools + sudo zypper install unixODBC-devel + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc + +**macOS** + + brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-mssql-release + brew update + brew install --no-sandbox msodbcsql + brew install mssql-tools + brew install autoconf + +*Note: Be sure to install PHP 7+ before proceeding to step 3. The Microsoft PHP Drivers for SQL Server will only work for PHP 7+. ### Step 3: Install the Microsoft PHP Drivers for SQL Server -*Note: The first step is not required in Mac OS X. PECL installs the stable version when version is not specified. You may run `sudo pecl search sqlsrv` to search for the latest releases and `sudo pecl install sqlsrv-[version]` to install a specific version. Drivers are Mac-compatible starting from `4.1.7preview` release. +*Note: You can run `sudo pecl search sqlsrv` to search for the latest releases and `sudo pecl install sqlsrv-[version]` to install a specific version. PECL installs the stable version when version is not specified. Drivers are Mac-compatible starting from `4.1.7preview` release. + +On Ubuntu, Debian, and SUSE systems only, run: sudo pear config-set php_ini `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` system - sudo pecl install sqlsrv - sudo pecl install pdo_sqlsrv + +On all systems, run: + + pecl install sqlsrv + pecl install pdo_sqlsrv ### Step 4: Install and Configure Apache #### PHP 7.0 -**Ubuntu** +**Ubuntu and Debian** sudo su apt-get install libapache2-mod-php7.0 apache2 @@ -232,19 +282,29 @@ The following instructions assume a clean environment and show how to install PH a2enmod php7.0 echo "extension=sqlsrv.so" >> /etc/php/7.0/apache2/php.ini echo "extension=pdo_sqlsrv.so" >> /etc/php/7.0/apache2/php.ini - exit - + **RedHat** - sudo yum install httpd + sudo su + yum install httpd + echo "extension=sqlsrv.so" > /etc/php.d/sqlsrv.ini + echo "extension=pdo_sqlsrv.so" > /etc/php.d/pdo_sqlsrv.ini -**Mac OS X** +**SUSE** + + sudo su + zypper install apache2 apache2-mod_php7 + a2enmod php7 + echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini + echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini + +**macOS** (echo ""; echo "SetHandler application/x-httpd-php"; echo "";) >> /usr/local/etc/apache2/2.4/httpd.conf #### PHP 7.1 -**Ubuntu** +**Ubuntu and Debian** sudo su apt-get install libapache2-mod-php7.1 apache2 @@ -253,35 +313,48 @@ The following instructions assume a clean environment and show how to install PH a2enmod php7.1 echo "extension=sqlsrv.so" >> /etc/php/7.1/apache2/php.ini echo "extension=pdo_sqlsrv.so" >> /etc/php/7.1/apache2/php.ini - exit - + **RedHat** - sudo yum install httpd + sudo su + yum install httpd + echo "extension=sqlsrv.so" > /etc/php.d/sqlsrv.ini + echo "extension=pdo_sqlsrv.so" > /etc/php.d/pdo_sqlsrv.ini -**Mac OS X** +**SUSE** + + sudo su + zypper install apache2 apache2-mod_php7 + a2enmod php7 + echo "extension=sqlsrv.so" >> /etc/php7/apache2/php.ini + echo "extension=pdo_sqlsrv.so" >> /etc/php7/apache2/php.ini + +**macOS** (echo ""; echo "SetHandler application/x-httpd-php"; echo "";) >> /usr/local/etc/apache2/2.4/httpd.conf - + ### Step 5: Restart Apache to load the new php.ini file -**Ubuntu** +**Ubuntu, Debian, and SUSE** - sudo service apache2 restart + sudo systemctl restart apache2 **RedHat** - sudo apachectl restart - -**Mac OS X** + sudo systemctl restart httpd - sudo apachectl restart +Note: On RedHat, SELinux is installed by default and runs in Enforcing mode. To allow Apache to connect to a database through SELinux, run the following command: + + sudo setsebool -P httpd_can_network_connect_db 1 + +**macOS** + + sudo apachectl restart -*Note to RedHat users: SELinux is installed by default and runs in Enforcing mode. To allow Apache to connect to database through SELinux, do this `sudo setsebool -P httpd_can_network_connect_db 1` ### Step 6: Create your sample app -Navigate to `/var/www/html` (`/usr/local/var/www/htdocs` on Mac) and create a new file called testsql.php. Copy and paste the following code in tetsql.php and change the servername, username, password and databasename. +Navigate to your system's document root -- `/var/www/html` on Ubuntu, Debian, and Redhat, `/srv/www/htdocs` on SUSE, or `/usr/local/var/www/htdocs` on Mac. Create a new file called testsql.php. Copy and paste the following code into testsql.php and change the servername, username, password and databasename. -src` directory, which is often unnecessary + +6. If you choose not to download from a GitHub repository, you will be asked to provide the full path to your local Source folder. + +7. If the compilation is successful, you will be given the option to rebuild or quit. + +#### Troubleshooting + +If something went wrong or the build failed, the log file will be launched (you can find the log files in `C:\php-sdk`). Otherwise, the log file will not be shown, and they remain in `C:\php-sdk` until you remove them manually. + +In addition to the log files in `C:\php-sdk`, you can examine the contents of `C:\php-sdk\phpsdk-build-task.bat`, which is overwritten every time you run the build scripts. + +#### Testing mode and/or setting alternative destination + +If your main goal is to build the drivers for testing, and/or there is no need to keep the `php-sdk` directory around, you can invoke `py builddrivers.py` with the necessary command-line arguments plus `--TESTING`, which turns on the *testing* mode (it is False by default). + +Setting the testing mode automatically turns off the looping mechanism. When the build is finished, you will find a copy of the drivers (unless the build failed) and the `php-sdk` folder in the same directory of these Python scripts. + +In addition, you can set an alternative destination using `--DESTPATH=`, which is **None** by default. Note that these two options are *not* available in the interactive mode. However, they are particularly useful for testing purposes (such as testing in a virtual machine) in which these build scripts are copied to a temporary folder. After the drivers have been successfully compiled and copied to the designated location, the temporary folder can be safely removed. + + + + + diff --git a/buildscripts/builddrivers.py b/buildscripts/builddrivers.py new file mode 100644 index 00000000..f4e14e34 --- /dev/null +++ b/buildscripts/builddrivers.py @@ -0,0 +1,288 @@ +#!/usr/bin/python3 +######################################################################################### +# +# Description: This script helps to build drivers in a Windows environment for PHP 7+ (32-bit/64-bit) +# +# Requirement: +# python 3.x +# PHP SDK and PHP Source +# Driver source code folder / GitHub repository +# Visual Studio 2015 (PHP 7.0* and 7.1*) and Visual Studio 2017 (PHP 7.2*) +# +# Execution: Run with command line with required options. +# Examples: +# py builddrivers.py (for interactive mode) +# py builddrivers.py --PHPVER=7.0.22 --ARCH=x64 --THREAD=nts --DRIVER=all --DEBUG +# +# Output: Build the drivers using PHP SDK. When running for local development, if build is unsuccessful, +# the log file will be launched for examination. Otherwise, the drivers will be renamed +# and copied to the designated location (if defined). +# +############################################################################################# + +import sys +import shutil +import os.path +import argparse +from buildtools import BuildUtil + +class BuildDriver(object): + """Build sqlsrv and/or pdo_sqlsrv drivers with PHP source with the following properties: + + Attributes: + util # BuildUtil object whose constructor takes phpver, driver, arch, thread, debug + repo # GitHub repository + branch # GitHub repository branch + download_source # download source from GitHub or not + dest_path # alternative destination for the drivers (None for development builds) + rebuild # a boolean flag - whether the user is rebuilding + make_clean # a boolean flag - whether make clean is necessary + source_path # path to a local source folder + testing # whether the user has turned on testing mode + """ + + def __init__(self, phpver, driver, arch, thread, debug, repo, branch, download, path, testing): + self.util = BuildUtil(phpver, driver, arch, thread, debug) + self.repo = repo + self.branch = branch + self.download_source = download + self.dest_path = path + self.testing = testing + self.rebuild = False + self.make_clean = False + self.source_path = None # None initially but will be set later if not downloading from GitHub + + def show_config(self): + print() + print('PHP Version: ', self.util.phpver) + print('Arch: ', self.util.arch) + print('Thread: ', self.util.thread) + print('Driver: ', self.util.driver) + print('Debug enabled: ', self.util.debug_enabled) + print() + + def clean_or_remove(self, root_dir, work_dir): + """Only check this for local development and not rebuilding. If the php source directory + already exists, this will prompt user whether to rebuild, clean, or superclean, the last option + will remove the entire php source directory. + + :param root_dir: the C:\ drive + :param work_dir: the directory of this script + :outcome: the old binaries, if exist, will be removed + """ + phpsrc = self.util.phpsrc_root(root_dir) + if os.path.exists( phpsrc ): + print(phpsrc + " exists.") + build_choice = validate_input("(r)ebuild for the same configuration, (c)lean otherwise, (s)uperclean if unsure ", "r/c/s") + self.make_clean = False + if build_choice == 'r': + print('Will rebuild the binaries') + # only the old binaries based on the current configuration will be removed + self.util.remove_prev_build(root_dir) + elif build_choice == 'c': + print('Will make clean') + self.make_clean = True + # all old builds are removed, and this step is necessary because + # the user might have changed the configuration + self.util.remove_old_builds(root_dir) + else: + print('Will remove ' + phpsrc) + os.system('RMDIR /s /q ' + phpsrc) + + os.chdir(work_dir) # change back to the working directory + + def build_extensions(self, root_dir, logfile): + """This takes care of getting the drivers' source files, building the drivers. + If dest_path is defined, the binaries will be copied to the designated destinations. + + :param root_dir: the root directory + :param logfile: the name of the logfile + :outcome: the drivers and symbols will renamed and placed in the appropriate location(s) + + """ + work_dir = os.path.dirname(os.path.realpath(__file__)) + + if self.download_source: + # This will download from the specified branch on GitHub repo and copy the source + self.util.download_msphpsql_source(repo, branch) + else: + # This case only happens when building for development + while True: + if self.source_path is None: + source = input('Enter the full path to the Source folder: ') + else: + source = input("Hit ENTER to reuse '" + self.source_path + "' or provide another path to the Source folder: ") + if len(source) == 0: + source = self.source_path + + valid = True + if os.path.exists(source) and os.path.exists(os.path.join(source, 'shared')): + # Checking the existence of 'shared' folder only, assuming + # sqlsrv and/or pdo_sqlsrv are also present if it exists + self.source_path = source + break + + print("The path provided is invalid. Please re-enter.") + + print('Copying source files from', source) + + os.system('ROBOCOPY ' + source + '\shared ' + work_dir + '\Source\shared /xx /xo ') + os.system('ROBOCOPY ' + source + '\sqlsrv ' + work_dir + '\Source\sqlsrv /xx /xo ') + os.system('ROBOCOPY ' + source + '\pdo_sqlsrv ' + work_dir + '\Source\pdo_sqlsrv /xx /xo ') + + print('Start building PHP with the extension...') + + # If not testing, dest should be the root drive. Otherwise, dest should be None. + dest = None if self.testing else root_dir + + # ext_dir is the directory where we can find the built extension(s) + ext_dir = self.util.build_drivers(self.make_clean, dest, logfile) + + # Copy the binaries if a destination path is defined + if self.dest_path is not None: + dest_drivers = os.path.join(self.dest_path, self.util.major_version(), self.util.arch) + dest_symbols = os.path.join(dest_drivers, 'Symbols', self.util.thread) + + # All intermediate directories will be created in order to create the leaf directory + if os.path.exists(dest_symbols) == False: + os.makedirs(dest_symbols) + + # Now copy all the binaries + if self.util.driver == 'all': + self.util.copy_binary(ext_dir, dest_drivers, 'sqlsrv', '.dll') + self.util.copy_binary(ext_dir, dest_symbols, 'sqlsrv', '.pdb') + self.util.copy_binary(ext_dir, dest_drivers, 'pdo_sqlsrv', '.dll') + self.util.copy_binary(ext_dir, dest_symbols, 'pdo_sqlsrv', '.pdb') + else: + self.util.copy_binary(ext_dir, dest_drivers, self.util.driver, '.dll') + self.util.copy_binary(ext_dir, dest_symbols, self.util.driver, '.pdb') + + + def build(self): + """This is the main entry point of building drivers for PHP. + For development, this will loop till the user decides to quit. + """ + self.show_config() + + work_dir = os.path.dirname(os.path.realpath(__file__)) + root_dir = 'C:' + os.sep + + quit = False + while not quit: + if not self.rebuild and not self.testing: + self.clean_or_remove(root_dir, work_dir) + + logfile = self.util.get_logfile_name() + + try: + self.build_extensions(root_dir, logfile) + print('Build Completed') + except: + print('Something went wrong, launching log file', logfile) + # display log file only when not testing + if not self.testing: + os.startfile(os.path.join(root_dir, 'php-sdk', logfile)) + os.chdir(work_dir) + break + + if not self.testing: + choice = input("Rebuild using the same configuration(yes) or quit (no) [yes/no]: ") + choice = choice.lower() + if choice == 'yes' or choice == 'y' or choice == '': + print('Rebuilding drivers...') + self.make_clean = False + self.rebuild = True + self.util.remove_prev_build(root_dir) + else: + quit = True + else: + quit = True + + os.chdir(work_dir) + +def validate_input(question, values): + """Return the user selected value, and it must be valid based on *values*.""" + while True: + options = values.split('/') + prompt = '[' + values + ']' + value = input(question + prompt + ': ') + value = value.lower() + if not value in options: + print("An invalid choice is entered. Choose from", prompt) + else: + break + return value + +################################### Main Function ################################### +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--PHPVER', help="PHP version, e.g. 7.1.*, 7.2.* etc.") + parser.add_argument('--ARCH', choices=['x64', 'x86']) + parser.add_argument('--THREAD', choices=['nts', 'ts']) + parser.add_argument('--DRIVER', default='all', choices=['all', 'sqlsrv', 'pdo_sqlsrv'], help="driver to build (default: all)") + parser.add_argument('--DEBUG', action='store_true', help="enable debug mode (default: False)") + parser.add_argument('--REPO', default='Microsoft', help="GitHub repository (default: Microsoft)") + parser.add_argument('--BRANCH', default='dev', help="GitHub repository branch (default: dev)") + parser.add_argument('--SOURCE', action='store_true', help="get source from a local path (default: False)") + parser.add_argument('--TESTING', action='store_true', help="turns on testing mode (default: False)") + parser.add_argument('--DESTPATH', default=None, help="an alternative destination for the drivers (default: None)") + + args = parser.parse_args() + + phpver = args.PHPVER + arch = args.ARCH + thread = args.THREAD + driver = args.DRIVER + debug = args.DEBUG + repo = args.REPO + branch = args.BRANCH + download = args.SOURCE is False + path = args.DESTPATH + testing = args.TESTING + + if phpver is None: + # starts interactive mode, testing mode is False + # will not prompt for drivers' destination path, which is None by default + while True: + # perform some minimal checks + phpver = input("PHP Version (e.g. 7.1.* or 7.2.*): ") + if phpver == '': + print('Empty PHP version entered! Please try again.') + elif phpver[0] < '7': + print('Only PHP 7.0 or above is supported. Please try again.') + else: + break + + arch_version = input("64-bit? [y/n]: ") + thread = validate_input("Thread safe? ", "nts/ts") + driver = validate_input("Driver to build? ", "all/sqlsrv/pdo_sqlsrv") + debug_mode = input("Debug enabled? [y/n]: ") + + answer = input("Download source from a GitHub repo? [y/n]: ") + download = False + if answer == 'yes' or answer == 'y' or answer == '': + download = True + repo = input("Name of the repo (hit enter for 'Microsoft'): ") + branch = input("Name of the branch (hit enter for 'dev'): ") + if repo == '': + repo = 'Microsoft' + if branch == '': + branch = 'dev' + + arch_version = arch_version.lower() + arch = 'x64' if arch_version == 'yes' or arch_version == 'y' or arch_version == '' else 'x86' + + debug_mode = debug_mode.lower() + debug = debug_mode == 'yes' or debug_mode == 'y' or debug_mode == '' + + builder = BuildDriver(phpver, + driver, + arch, + thread, + debug, + repo, + branch, + download, + path, + testing) + builder.build() diff --git a/buildscripts/buildtools.py b/buildscripts/buildtools.py new file mode 100644 index 00000000..2176b94e --- /dev/null +++ b/buildscripts/buildtools.py @@ -0,0 +1,476 @@ +#!/usr/bin/python3 +######################################################################################### +# +# Description: The class BuildUtil will build Microsoft SQL Server PHP 7+ Drivers +# for 32 bit and 64 bit. +# +# Requirement: +# python 3.x +# PHP SDK and PHP Source +# Driver source code folder +# Git for Windows +# Visual Studio 2015 (PHP 7.0* and 7.1*) and Visual Studio 2017 (PHP 7.2*) +# +# Output: The drivers will be renamed and copied to the specified location. +# +############################################################################################# + +import shutil +import os.path +import stat +import datetime +import urllib.request +import zipfile +import fileinput + +class BuildUtil(object): + """Build sqlsrv and/or pdo_sqlsrv drivers with PHP source with the following properties: + + Attributes: + phpver # PHP version, e.g. 7.1.*, 7.2.* etc. + driver # all, sqlsrv, or pdo_sqlsrv + arch # x64 or x86 + thread # nts or ts + debug_enabled # whether debug is enabled + """ + + def __init__(self, phpver, driver, arch, thread, debug_enabled = False): + self.phpver = phpver + self.driver = driver.lower() + self.arch = arch.lower() + self.thread = thread.lower() + self.debug_enabled = debug_enabled + + def major_version(self): + """Return the major version number based on the PHP version.""" + return self.phpver[0:3] + + def version_label(self): + """Return the version label based on the PHP version.""" + major_ver = self.major_version() + + if major_ver[2] == '0': + version = major_ver[0] + else: + version = major_ver[0] + major_ver[2] + return version + + def driver_name(self, driver, suffix): + """Return the *driver* name with *suffix* after PHP is successfully compiled.""" + return 'php_' + driver + suffix + + def driver_new_name(self, driver, suffix): + """Return the *driver* name with *suffix* based on PHP version and thread.""" + version = self.version_label() + return 'php_' + driver + '_' + version + '_' + self.thread + suffix + + def compiler_version(self): + """Return the appropriate compiler version based on PHP version.""" + VC = 'vc14' + version = self.version_label() + if version >= '72': # Compiler version for PHP 7.2 or above + VC = 'vc15' + return VC + + def phpsrc_root(self, sdk_dir): + """Return the path to the PHP source folder based on *sdk_dir*.""" + vc = self.compiler_version() + return os.path.join(sdk_dir, 'php-sdk', 'phpdev', vc, self.arch, 'php-'+self.phpver+'-src') + + def build_abs_path(self, sdk_dir): + """Return the absolute path to the PHP build folder based on *sdk_dir*.""" + phpsrc = self.phpsrc_root(sdk_dir) + + build_dir = 'Release' + if self.debug_enabled: + build_dir = 'Debug' + + if self.thread == 'ts': + build_dir = build_dir + '_TS' + + if self.arch == 'x64': + build_dir = self.arch + os.sep + build_dir + + return os.path.join(phpsrc, build_dir) + + def remove_old_builds(self, sdk_dir): + """Remove the extensions, e.g. the driver subfolders in php-7.*-src\ext.""" + print('Removing old builds...') + + phpsrc = self.phpsrc_root(sdk_dir) + ext_path = os.path.join(phpsrc, 'ext') + if os.path.exists( ext_path ): + shutil.rmtree(os.path.join(ext_path, 'sqlsrv'), ignore_errors=True) + shutil.rmtree(os.path.join(ext_path, 'pdo_sqlsrv'), ignore_errors=True) + + if self.arch == 'x64': + shutil.rmtree(os.path.join(phpsrc, self.arch), ignore_errors=True) + else: + shutil.rmtree(os.path.join(phpsrc, 'Debug'), ignore_errors=True) + shutil.rmtree(os.path.join(phpsrc, 'Debug_TS'), ignore_errors=True) + shutil.rmtree(os.path.join(phpsrc, 'Release'), ignore_errors=True) + shutil.rmtree(os.path.join(phpsrc, 'Release_TS'), ignore_errors=True) + + def remove_prev_build(self, sdk_dir): + """Remove all binaries and source code in the Release* or Debug* + folders according to the current configuration + """ + print('Removing previous build...') + build_dir = self.build_abs_path(sdk_dir) + if not os.path.exists(build_dir): + return + + os.chdir(build_dir) + os.system('DEL *sqlsrv*') + + # remove the extensions in the phpsrc's release* or debug* folder's ext subfolder + release_ext_path = os.path.join(build_dir, 'ext') + if os.path.exists( release_ext_path ): + shutil.rmtree(os.path.join(release_ext_path, 'sqlsrv'), ignore_errors=True) + shutil.rmtree(os.path.join(release_ext_path, 'pdo_sqlsrv'), ignore_errors=True) + + # next remove the binaries too + os.chdir(release_ext_path) + os.system('DEL *sqlsrv*') + + @staticmethod + def get_logfile_name(): + """Return the filename for the log file based on timestamp.""" + return 'Build_' + datetime.datetime.now().strftime("%Y%m%d_%H%M") + '.log' + + @staticmethod + def update_file_content(file, search_str, new_str): + """Find *search_str* and replace it by *new_str* in a *file*""" + os.chmod(file, stat.S_IWRITE) + with fileinput.FileInput(file, inplace=True) as f: + for line in f: + print(line.replace(search_str, new_str), end='') + + @staticmethod + def generateMMDD(): + """Return the generated Microsoft PHP Build Version Number""" + d = datetime.date.today() + + startYear = 2009 + startMonth = 4 + passYear = int( '%02d' % d.year ) - startYear + passMonth = int( '%02d' % d.month ) - startMonth + MM = passYear * 12 + passMonth + dd = d.day + + MMDD = "" + str( MM ) + if( dd < 10 ): + return MMDD + "0" + str( dd ) + else: + return MMDD + str( dd ) + + @staticmethod + def get_driver_version(version_file): + """Read the *version_file* and return the driver version.""" + with open(version_file) as f: + for line in f: + if 'SQLVERSION_MAJOR' in line: # major version + major = line.split()[2] + elif 'SQLVERSION_MINOR' in line: # minor version + minor = line.split()[2] + elif 'SQLVERSION_PATCH' in line: # patch + patch = line.split()[2] + break + + return major + '.' + minor + '.' + patch + + @staticmethod + def write_lines_to_copy_source(driver, file): + """Write to file the commands to copy *driver* source.""" + source = '%currDir%' + os.sep + 'Source' + os.sep + driver + dest = '%phpSrc%' + os.sep + 'ext' + os.sep + driver + file.write('@CALL ROBOCOPY ' + source + ' ' + dest + ' /s /xx /xo' + os.linesep) + + source = '%currDir%' + os.sep + 'Source' + os.sep + 'shared' + dest = '%phpSrc%' + os.sep + 'ext' + os.sep + driver + os.sep + 'shared' + file.write('@CALL ROBOCOPY ' + source + ' ' + dest + ' /s /xx /xo' + os.linesep) + + @staticmethod + def download_msphpsql_source(repo, branch, dest_folder = 'Source', clean_up = True): + """Download to *dest_folder* the msphpsql archive of the specified + GitHub *repo* and *branch*. The downloaded files will be removed by default. + """ + try: + work_dir = os.path.dirname(os.path.realpath(__file__)) + + temppath = os.path.join(work_dir, 'temp') + if os.path.exists(temppath): + shutil.rmtree(temppath) + os.makedirs(temppath) + os.chdir(temppath) + + file = branch + '.zip' + url = 'https://github.com/' + repo + '/msphpsql/archive/' + branch + '.zip' + + print('Downloading ' + url + ' ...') + try: + with urllib.request.urlopen(url) as response, open(file, 'wb') as out_file: + shutil.copyfileobj(response, out_file) + except: + print ("Resort to skip ssl verification...") + # need to skip ssl verification on some agents + # see https://www.python.org/dev/peps/pep-0476/ + with urllib.request.urlopen(url, context=ssl._create_unverified_context()) as response, open(file, 'wb') as out_file: + shutil.copyfileobj(response, out_file) + + print('Extracting ' + file + ' ...') + zip = zipfile.ZipFile(file) + zip.extractall() + zip.close() + + msphpsqlFolder = os.path.join(temppath, 'msphpsql-' + branch) + source = os.path.join(msphpsqlFolder, 'source') + os.chdir(work_dir) + + os.system('ROBOCOPY ' + source + '\shared ' + dest_folder + '\shared /xx /xo') + os.system('ROBOCOPY ' + source + '\pdo_sqlsrv ' + dest_folder + '\pdo_sqlsrv /xx /xo') + os.system('ROBOCOPY ' + source + '\sqlsrv ' + dest_folder + '\sqlsrv /xx /xo') + + if clean_up: + shutil.rmtree(temppath) + + except: + print('Error occurred when downloading source') + raise + + def update_driver_source(self, source_dir, driver): + """Update the *driver* source in *source_path* with the + latest version, file descriptions, etc. + If debug is enabled, will remove the optimization flag + """ + driver_dir = os.path.join(source_dir, driver) + + if self.debug_enabled: + # Remove the optimization flag in the config file for this driver + # because '/O2' option is incompatible with Debug mode + print('Removing optimization flag for', driver) + config_file = os.path.join(driver_dir, 'config.w32') + if driver == 'sqlsrv': + self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_SQLSRV", "/O2" );', '') + elif driver == 'pdo_sqlsrv': + self.update_file_content(config_file, 'ADD_FLAG( "CFLAGS_PDO_SQLSRV", "/O2" );', '') + + # Update Template.rc + template_file = os.path.join(driver_dir, 'template.rc') + if driver == 'sqlsrv': + drivername = self.driver_new_name(driver, '.dll') + self.update_file_content(template_file, 'FILE_NAME \"\\0\"', '"' + drivername + '\\0"') + self.update_file_content(template_file, '\"Microsoft Drivers for PHP for SQL Server\\0\"', '"Microsoft Drivers for PHP for SQL Server (SQLSRV Driver)\\0"') + elif driver == 'pdo_sqlsrv': + drivername = self.driver_new_name(driver, '.dll') + self.update_file_content(template_file, 'FILE_NAME \"\\0\"', '"' + drivername + '\\0"') + self.update_file_content(template_file, '\"Microsoft Drivers for PHP for SQL Server\\0\"', '"Microsoft Drivers for PHP for SQL Server (PDO Driver)\\0"') + + # Update Version.h + version_file = os.path.join(source_dir, 'shared', 'version.h') + build_number = self.generateMMDD() + self.update_file_content(version_file, 'SQLVERSION_BUILD 0', 'SQLVERSION_BUILD ' + build_number) + + # get the latest version + version = self.get_driver_version(version_file) + '.' + build_number + print('Driver version is: ', version) + + # Update CREDIT file + credits_file = os.path.join(driver_dir, 'CREDITS') + if driver == 'sqlsrv': + self.update_file_content(credits_file, 'Microsoft Drivers for PHP for SQL Server', 'Microsoft Drivers ' + version + ' for PHP for SQL Server (' + self.driver.upper() + ' driver)') + elif driver == 'pdo_sqlsrv': + self.update_file_content(credits_file, 'Microsoft Drivers for PHP for SQL Server (PDO driver)', 'Microsoft Drivers ' + version + ' for PHP for SQL Server (' + self.driver.upper() + ' driver)') + + def generate_build_options(self): + """Return the generated build configuration and arguments""" + cmd_line = '' + if self.debug_enabled: + cmd_line = ' --enable-debug ' + + if self.driver == 'all': + cmd_line = ' --enable-sqlsrv=shared --enable-pdo --with-pdo-sqlsrv=shared ' + cmd_line + else: + if self.driver == 'sqlsrv': + cmd_line = ' --enable-sqlsrv=shared ' + cmd_line + else: # pdo_sqlsrv + cmd_line = ' --enable-pdo --with-pdo-sqlsrv=shared ' + cmd_line + + cmd_line = 'cscript configure.js --disable-all --enable-cli --enable-cgi --enable-embed' + cmd_line + if self.thread == 'nts': + cmd_line = cmd_line + ' --disable-zts' + return cmd_line + + def create_local_batch_file(self, make_clean, cmd_line, log_file): + """Generate the batch file to be picked up by the PHP starter script.""" + filename = 'phpsdk-build-task.bat' + print('Generating ', filename) + try: + file = open(filename, 'w') + file.write('@ECHO OFF' + os.linesep) + file.write('SET currDir=%CD%' + os.linesep) + file.write('SET LOG_NAME=%currDir%\\' + log_file + os.linesep) + file.write('@CALL phpsdk_buildtree phpdev > %LOG_NAME% 2>&1' + os.linesep) + + # for PHP version with release tags, such as 'RC', 'beta', etc. + # we need to remove the hyphen '-' between the version number and tag + # because in https://github.com/php/php-src the released tags have no hyphens + + php_tag = 'php-' + self.phpver.replace('-', '') + php_src = 'php-' + self.phpver +'-src' + + # if not exists, check out the specified tag + file.write('IF NOT EXIST ' + php_src + ' @CALL git clone -b ' + php_tag + ' --depth 1 --single-branch https://github.com/php/php-src.git ' + php_src + os.linesep) + file.write('CD ' + php_src + os.linesep) + file.write('SET phpSrc=%CD%' + os.linesep) + file.write('@CALL phpsdk_deps -u >> %LOG_NAME% 2>&1' + os.linesep) + + # copy source files to extension + if self.driver == 'all': + self.write_lines_to_copy_source('sqlsrv', file) + self.write_lines_to_copy_source('pdo_sqlsrv', file) + else: + self.write_lines_to_copy_source(self.driver, file) + + # configure and build + file.write('@CALL buildconf --force >> %LOG_NAME% 2>&1' + os.linesep) + file.write('@CALL ' + cmd_line + ' >> %LOG_NAME% 2>&1' + os.linesep) + if make_clean: + file.write('nmake clean >> %LOG_NAME% 2>&1' + os.linesep) + file.write('nmake >> %LOG_NAME% 2>&1' + os.linesep) + file.write('exit' + os.linesep) + file.close() + return filename + except: + print('Cannot create ', filename) + + def build_drivers(self, make_clean = False, dest = None, log_file = None): + """Build sqlsrv/pdo_sqlsrv extensions for PHP, assuming the Source folder + exists in the working directory, and this folder will be removed when the build + is complete. + """ + work_dir = os.path.dirname(os.path.realpath(__file__)) + + # First, update the driver source file contents + source_dir = os.path.join(work_dir, 'Source') + if self.driver == 'all': + self.update_driver_source(source_dir, 'sqlsrv') + self.update_driver_source(source_dir, 'pdo_sqlsrv') + else: + self.update_driver_source(source_dir, self.driver) + + # Next, generate the build configuration and arguments + cmd_line = self.generate_build_options() + print('cmd_line: ' + cmd_line) + + # Generate a batch file based on the inputs + if log_file is None: + log_file = self.get_logfile_name() + + batch_file = self.create_local_batch_file(make_clean, cmd_line, log_file) + + # Reference: https://github.com/OSTC/php-sdk-binary-tools + # Clone the master branch of PHP sdk if the directory does not exist + print('Downloading the latest php SDK...') + + # if *dest* is None, simply use the current working directory + sdk_dir = dest + copy_to_ext = True # this determines where to copy the binaries to + if dest is None: + sdk_dir = work_dir + copy_to_ext = False + + phpSDK = os.path.join(sdk_dir, 'php-sdk') + if not os.path.exists( phpSDK ): + os.system('git clone https://github.com/OSTC/php-sdk-binary-tools.git --branch master --single-branch --depth 1 ' + phpSDK) + os.chdir(phpSDK) + os.system('git pull ') + + # Move the generated batch file to phpSDK for the php starter script + sdk_batch_file = os.path.join(phpSDK, batch_file) + if os.path.exists(sdk_batch_file): + os.remove(sdk_batch_file) + shutil.move(os.path.join(work_dir, batch_file), phpSDK) + + sdk_source = os.path.join(phpSDK, 'Source') + # Sometimes, for various reasons, the Source folder from previous build + # might exist in phpSDK. If so, remove it first + if os.path.exists(sdk_source): + os.chmod(sdk_source, stat.S_IWRITE) + shutil.rmtree(sdk_source, ignore_errors=True) + shutil.move(source_dir, phpSDK) + + # Invoke phpsdk--.bat + vc = self.compiler_version() + starter_script = 'phpsdk-' + vc + '-' + self.arch + '.bat' + print('Running starter script: ', starter_script) + os.system(starter_script + ' -t ' + batch_file) + + # Now we can safely remove the Source folder, because its contents have + # already been modified prior to building the extensions + shutil.rmtree(os.path.join(phpSDK, 'Source'), ignore_errors=True) + + # Next, rename the newly compiled PHP extensions + self.rename_binaries(sdk_dir) + + # Final step, copy the binaries to the right place + ext_dir = self.copy_binaries(sdk_dir, copy_to_ext) + return ext_dir + + def rename_binary(self, path, driver): + """Rename the *driver* binary (sqlsrv or pdo_sqlsrv) (only the dlls).""" + driver_old_name = self.driver_name(driver, '.dll') + driver_new_name = self.driver_new_name(driver, '.dll') + + os.rename(os.path.join(path, driver_old_name), os.path.join(path, driver_new_name)) + + def rename_binaries(self, sdk_dir): + """Rename the sqlsrv and/or pdo_sqlsrv dlls according to the PHP + version and thread. + """ + + # Derive the path to where the extensions are located + ext_dir = self.build_abs_path(sdk_dir) + print("Renaming binaries in ", ext_dir) + + if self.driver == 'all': + self.rename_binary(ext_dir, 'sqlsrv') + self.rename_binary(ext_dir, 'pdo_sqlsrv') + else: + self.rename_binary(ext_dir, self.driver) + + def copy_binary(self, from_dir, dest_dir, driver, suffix): + """Copy sqlsrv or pdo_sqlsrv binary (based on *suffix*) to *dest_dir*.""" + if suffix == '.dll': + binary = self.driver_new_name(driver, suffix) + else: + binary = self.driver_name(driver, suffix) + shutil.copy2(os.path.join(from_dir, binary), dest_dir) + + def copy_binaries(self, sdk_dir, copy_to_ext): + """Copy the sqlsrv and/or pdo_sqlsrv binaries, including the pdb files, + to the right place, depending on *copy_to_ext*. The default is to + copy them to the 'ext' folder. + """ + build_dir = self.build_abs_path(sdk_dir) + print('Copying the binaries from', build_dir) + if copy_to_ext: + dest_dir = os.path.join(build_dir, 'ext') + else: + # Simply make a copy of the binaries in sdk_dir + dest_dir = sdk_dir + + print('Destination:', dest_dir) + + # Now copy the binaries + if self.driver == 'all': + self.copy_binary(build_dir, dest_dir, 'sqlsrv', '.dll') + self.copy_binary(build_dir, dest_dir, 'sqlsrv', '.pdb') + self.copy_binary(build_dir, dest_dir, 'pdo_sqlsrv', '.dll') + self.copy_binary(build_dir, dest_dir, 'pdo_sqlsrv', '.pdb') + else: + self.copy_binary(build_dir, dest_dir, self.driver, '.dll') + self.copy_binary(build_dir, dest_dir, self.driver, '.pdb') + + return dest_dir + diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 00000000..ffa47b4b --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,16 @@ +set -e + +testConnection="/opt/mssql-tools/bin/sqlcmd -S sql -U sa -P Password123" + +for run in {1..10}; do + +>&2 echo "SQL Server is starting up.." +if $testConnection; then + >&2 echo "SQL Server is up!" + break; +else + sleep 6 +fi +done + + diff --git a/test/Performance/README.md b/test/Performance/README.md index 1929d1de..b45fb9e0 100644 --- a/test/Performance/README.md +++ b/test/Performance/README.md @@ -34,16 +34,6 @@ On Linux and Mac, the script must be executed with `sudo python3` because to ena python3 run-perf_tests.py -platform | tee run-perf_output.txt -<<<<<<< HEAD `-platform` - The platform that the tests are ran on. Must be one of the following: Windows10, WindowsServer2016, WindowsServer2012, Ubuntu16, RedHat7, Sierra. `-php-driver` (optional) - The driver that the tests are ran on. Must be one of the following: sqlsrv, pdo_sqlsrv, or both. Default is both. -`-test-only` (optional) - The test to run. Must be the file name (not including path) of one test or 'all'. Default is 'all'. If one test is specified, must also specify the -php-driver option to sqlsrv or pdo_sqlsrv. -======= -`-platform` - The platform that the tests are ran on. Must be one of the following: Windows10, WindowsServer2016, WindowsServer2012, Ubuntu16, RedHat7, Sierra. -`-iterations` - The number of iterations for regular tests. -`-iterations-large` - The number of iterations for the tests that fetch large data. Usually set to 1. -`-result-server` - The server containing the result database. It is assumed that the result database s already setup before running the tests. -`-result-db` - Database name. With the current result database setup files, this should be set to `TestResults`. -`-result-uid` - Result database username. -`-result-pwd` - Result database password. ->>>>>>> upstream/dev +`-test-only` (optional) - The test to run. Must be the file name (not including path) of one test or 'all'. Default is 'all'. If one test is specified, must also specify the -php-driver option to sqlsrv or pdo_sqlsrv. \ No newline at end of file diff --git a/test/Performance/setup_env_unix.sh b/test/Performance/setup_env_unix.sh index d5341bfd..a2f51cb0 100644 --- a/test/Performance/setup_env_unix.sh +++ b/test/Performance/setup_env_unix.sh @@ -85,33 +85,6 @@ elif [ $PLATFORM = "RedHat7" ]; then printf "done\n" elif [ $PLATFORM = "Sierra" ]; then -<<<<<<< HEAD - echo "Installing homebrew..." - yes | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" >> env_setup.log 2>&1 - echo "OK" - echo "Installing wget..." - brew install wget >> env_setup.log 2>&1 - echo "OK" - echo "Installing svn..." - brew install svn >> env_setup.log 2>&1 - echo "OK" - echo "Installing openssl..." - brew install pkg-config >> env_setup.log 2>&1 - brew install openssl >> env_setup.log 2>&1 - echo "OK" - echo "Installing python3..." - brew install python3 >> env_setup.log 2>&1 - echo "OK" - echo "Installing MSODBCSQL..." - brew tap microsoft/msodbcsql https://github.com/Microsoft/homebrew-msodbcsql >> env_setup.log 2>&1 - brew update >> env_setup.log 2>&1 - yes | ACCEPT_EULA=Y brew install --no-sandbox msodbcsql >> env_setup.log 2>&1 - echo "OK" - yes | brew install autoconf >> env_setup.log 2>&1 - echo "Installing pyodbc..." - pip3 install pyodbc >> env_setup.log 2>&1 - echo "OK" -======= printf "Installing homebrew..." yes | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" >> env_setup.log printf "done\n" @@ -143,7 +116,6 @@ elif [ $PLATFORM = "Sierra" ]; then printf "Installing pyodbc..." pip3 install pyodbc >> env_setup.log printf "done\n" ->>>>>>> upstream/dev fi printf "Downloading PHP-$PHP_VERSION source tarball..."