PHP. Javascript. Редактирование имени файлов перед отправкой на сервер

Как известно, со стороны javascript мы не можем обратиться напрямую к файлу или файлам. Единственное, можно лишь получить имя файла. Допустим, перед нами поставили задачу, организовать возможность до загрузки файла на сервер редактировать имя выбранного файла. В лоб это невозможно, но можно воспользоваться обходным путем: 1 - нужно попытаться как-то скрыть стандартный элемент обозревателя файлов, 2 - организовать вспомогательные интерфейсы, способные вызывать обозреватель файлов и получать в свое распоряжение имя файла, 3 - при сохранении файла на стороне сервера подменять имя файла на редактируемое.
Ниже представлено одно из решений данной задачки. Обратите внимание на хак, скрывающего стандартный элемент обозревателя файлов. Также в интерфейсе редактирования имени файла использован атрибут - readonly, если попытаться использовать - disabled, для предупреждения режима редактирования файла, но тогда фактически из формы будет исключен данный элемент, а значит невозможно будет отсылать редактируемое имя серверу. Решение протестировано на большинстве браузеров свежих релизов. 

<?php
    if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'save') {
      
        if (!empty($_FILES['file']['name'])) {
      
            $short_name = $_REQUEST['short_name'];
            $exstension = !empty($_REQUEST['exstension']) ? '.'.$_REQUEST['exstension'] : '';
            $file_name     = $short_name.$exstension;
            $upload_dir = "./files/test";
      
            if (!file_exists($upload_dir)) {
                mkdir($upload_dir);
            }
          
            if ($_FILES['file']['error'][0] == 0) {
                $upload_file = $upload_dir.'/'.$file_name;
                move_uploaded_file($_FILES['file']['tmp_name'][0], $upload_file);
            }
      
        }
  
    }
?>

<html>
  
<head>
    <title>test</title>
</head>

<style>

    #choose_btn {
        width: 80px;
    }
  
    #submit_btn {
        width: 80px;
    }
  
    #file_view table {
        width: 300px;
    }
  
    #file_view {
        background: #FFF;
        border: solid #364658;
        border-width: 1px;
        width: 300px;
    }
  
    #file_view td {
        width: 100px;
        border: solid #364658;
        border-width: 1px;
        text-align: center;
    }
  
    .input_file {
        position: absolute;
        margin-left: -9000px;
        -moz-opacity: 0;
        filter: alpha(opacity=0);
        opacity: 0.5;
    }

</style>

<script src="jquery.js"></script>

<script>
  
    $(document).on('change', '#input_file_btn', function(){
  
        var file                     = {};
            file.name              = this.value,
            win                        = /.*\\(.*)/,
            unix                       = /.*\/(.*)/,
            separator              = /\./,
            extension              = /\w+/,
            file.name               = file.name.replace(win, "$1"),
            file.name               = file.name.replace(unix, "$1"),
            file.name_parts    = file.name.split(separator),
            file.short_name    = file.name_parts[0],
            file.extension        = file.name_parts[file.name_parts.length - 1];
            file.extension        = file.name_parts.length > 1 && extension.test(file.extension) ? file.extension : '';
          
        $('#file_short_name').val(file.short_name);
        $('#file_exstension').val(file.extension);
      
        $('#file_short_name').prop('readonly', true);
      
    }).on('click', '#edit', function(){
  
        $('#file_short_name').prop('readonly', false);
  
    }).on('click', '#choose_btn', function(){
  
        $('#input_file_btn').trigger('click');
  
    });

</script>

<body>
 
    <form action="" method="post" enctype="multipart/form-data">
 
        <input type="hidden" name="action" value="save"/>
        <input type="file" name="file[]" id="input_file_btn" class="input_file"/>
      
        <div>
            <table id="file_view">
                <thead>
                    <tr>
                        <td>mode</td>
                        <td>file short name</td>
                        <td>file exstension</td>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>
                            <span id="edit" style="color: blue; border-bottom: 1px dashed; cursor: pointer;">
                                edit
                            </span>
                        </td>
                        <td>
                            <input type="text" id="file_short_name" name="short_name" readonly />
                        </td>
                        <td>
                            <input type="text" id="file_exstension" name="exstension" readonly />
                        </td>
                    </tr>
                </tbody>          
            </table>
        </div>
      
        <div>
            <input id="choose_btn" type="button" value="choose file"/>
            <input id="submit_btn" type="submit" value="save file"/>
        </div>
  
    </form>
 
</body>
  
</html>

PHP. Soap service. Remote Procedure Call. Разработка тестового веб-сервиса

Наш тестовый веб-сервис будет решать одну задачу: на любой входной запрос, состоящего из даты в формате - день.месяц.год - он должен возвращать дату в виде timestamp. Создадим для этого процедуру - test(). Итак, для разворачивания soap - сервиса необходимо убедиться в том, что в настройках разрешено использование soap - сервера и клиента

Далее выделяете необходимую директорию для последующих служебных файлов. В моем примере в корне хоста test.ru была выделена директория - /web_service, куда разместил следующие файлы:
.htaccess - поддержка веб - сервиса;
index.php - реализация движка веб - сервиса (класс соединения и вызываемые процедуры);
web_service.wsdl - описание нашего тестового веб - сервиса и доступа к нему;
test.php - для демонстрации работы веб - сервиса.
Ниже приведено их содержимое, думаю по ним не составит труда разобраться.

.htaccess

# Enables or disables WSDL caching feature.
php_flag soap.wsdl_cache_enabled 0

# Sets the directory name where SOAP extension will put cache files.
php_value soap.wsdl_cache_dir "/tmp"

# (time to live) Sets the number of second while cached file will be used
# instead of original one.
php_value soap.wsdl_cache_ttl 0


AddDefaultCharset utf8

index.php

<?php
   
    ini_set('soap.wsdl_cache_enabled', 'Off');
   
    class Connection
    {
        /*
            Возвращает заданную дату в виде timestamp.
            Формат даты - dd.mm.yyyy
        */
        function test($dt) {
       
            if (!empty($dt)) {
                $dt = explode('.', $dt);
                $time_stamp = mktime(0, 0, 0, $dt[1], $dt[0], $dt[2]);
                return $time_stamp;
            }
            else {
                return false;
            }
           
        }   
       
    }
   
    try
    {
        $server = new SoapServer('http://192.168.126.128/web_service/web_service.wsdl?'.rand());
        $server->setClass("Connection");
        $server->handle();
    }
    catch (ExceptionFileNotFound $e)
    {
        echo 'Error message: ' . $e->getMessage();
    }

?>


web_service.wsdl

<?xml version="1.0" encoding="utf-8"?>

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="webserviceService" targetNamespace="http://tempuri.org/" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/">

<message name="test_input">
    <part name="dt" type="xs:string"/>
</message>

<message name="test_output">
    <part name="request" type="xs:string"/>
</message>

<message name="null_response"/>

<portType name="Connection">
    <operation name="test">
        <input message="tns:test_input"/>
        <output message="tns:test_output"/>
    </operation>
</portType>

<binding name="bind_connect" type="tns:Connection">

    <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>

    <operation name="test">
        <soap:operation soapAction="urn:web-service#test" style="rpc"/>
        <input message="tns:test_input">
            <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:web-service"/>
        </input>
        <output message="tns:test_output">
            <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:web-service"/>
        </output>
    </operation>

</binding>

<service name="webserviceService">
    <port name="webservicePort" binding="tns:bind_connect">
        <soap:address location="http://
192.168.126.128/web_service/index.php"/>
    </port>
</service>

</definitions>


test.php

<?php

header('Content-type: text/html; charset=utf-8');
@set_time_limit(300);

try {
   
    $client = new SoapClient("http://192.168.126.128/web_service/web_service.wsdl?".rand(), 

                                                     array('trace' => 1, 'exceptions' => 1));
    echo 'test('.date("d.m.Y", time()).') = '.$client->test(strval(date("d.m.Y", time())));
   
}
catch (SoapFault $e) {

    echo "<pre>".print_r($e, true)."</pre>";
    echo "<br/><br/>Error Caught";

}

?>


Стоит отметить, что при инстанцировании soap-сервера и клиентов, а также в файле описания веб-сервиса, был использован ip-адрес веб-сервера, также можно использовать и непосредственное имя хоста (test.ru).
После завершения всех работ, пробуем протестировать наш веб-сервис. На запрос

http://test.ru/web_service/test.php

мы получаем ожидаемый ответ

test(27.03.2014) = 1395903600

Что говорит о работоспособности сервиса. Всем успеха. Исходники можно скачать по следующей ссылке - download

Javascript. Типовое сравнение объектов

Объявим пространство имен NS (регистрозависим)

var NS = {};

Далее объявим в нем конструктор Test и создадим на его основе экземпляр t

NS.Test = function() {
    this.name = 'Test';
};

NS.t = new NS.Test();


Далее создадим объект o, используя стандартный объект Object

NS.o = {};

Для определения принадлежности того или иного экземпляра своему "классу" (в js понятие класса условно), можно воспользоваться следующими стандартными способами

NS.t.constructor == NS.Test // true
NS.t instanceof NS.Test     // true

NS.o.constructor == Object     // true
NS.o instanceof Object         // true


Если попытаться сопоставить объект через явно объявленный конструктор с объектом Object,
то можно получить следующие результаты

NS.t.constructor == Object     // false
NS.t instanceof Object         // true


Первое сравнение вернуло false, это и понятно, так как этот конструктор явно объявлен и ссылается на функцию Test(), второе сравнение истинно потому, что сам конструктор является объектом, что уж там, в javascripte практически все представлено объектом, такова его реализация. В подтверждение сказанного приведу следующее сравнение

NS.Test.constructor == Object     // false
NS.Test instanceof Object         // true


В виде дополнения, приведу список встроенных в javascript объектов

// Массив пронумерованных элементов, также может служить стеком или очередью
Array

// Объект для булевых значений
Boolean

// Функции для работы с датой и временем
Date

// объект для представления ошибок
Error

// Ошибка при выполнении функции eval
EvalError

// Каждая функция в яваскрипт является объектом класса Function
Function

// Встроенный объект, предоставляющий константы и методы для математических вычислений
Math

// Объект для работы с числами
Number

// Базовый объект javascript
Object

// Ошибка, когда число не лежит в нужном диапазоне
RangeError

// Ошибку при ссылке на несуществующую переменную
ReferenceError

// Позволяет работать с регулярными выражениями.
RegExp

// Базовый объект для строк. Позволяет управлять текстовыми строками, форматировать их и выполнять поиск строк
String

// Ошибка при интерпретации синтаксически неверного кода
SyntaxError

// Ошибка в типе значения
TypeError

// Ошибка при некорректном URI
URIError


Небольшой пример сверки типа объекта

var stack = [];

if (stack instanceof Array) {
    stack.push(1);
    stack.push(2);
    stack.push(3);
}

Oracle. Get dates in russian language

select to_char(sysdate, 'Month', 'nls_date_language = russian') current_month from dual

Oracle. Особенности NULL значений

Как известно, в sql то или иное поле либо определено (NOT NULL), и тогда имеет определенное значение, либо не определено (NULL), и тогда с этими полями начинают обращаться более аккуратно, так как они могут вызвать неоднозначность и ошибочность в ожидаемом запросе. Для примера продемонстрирую следующий сценарий, в результатах которого (см. рисунок ниже) видно, как изменяется значение среднего арифметического значения, суммы значения, общего количества и количества строк со значащими значениями. Для сравнения поведения приведены строками ниже результаты подзапросов, где введена замещающая пустое значение на ноль функция nvl(). Видно, что при подсчетах пустые значения просто напросто не учитываются, функция nvl(), напротив, приводит к тому, что "пустые" значения включаются в расчет. 

with
  -- emulation of test table
  virt_table( id, val ) as (
    select 1, 1 from dual union all
    select 2, 2 from dual union all
    select 3, null from dual union all
    select 4, null from dual union all
    select 5, 5 from dual
  ),

  -- test data without nulls
  clear_nulls as (
    select id, nvl(val, 0) val from virt_table
  ),
  -- comparison of test data
  compare( count_rows, count_val, sum_val, avg1_val, avg2_val, avg3_val, commentary ) as (
    -- with nulls
    select
      count(*),
      count(val),
      sum(val),
      avg(val),
      sum(val) / count(val),
      sum(val) / count(*),
      'with nulls' commentary
    from virt_table
    union all
    -- without nulls
    select
      count(*),
      count(nvl(val, 0)),
      sum(nvl(val, 0)),
      avg(nvl(val, 0)),
      sum(nvl(val, 0)) / count(nvl(val, 0)),
      sum(nvl(val, 0)) / count(*),
      'manual cleaning of nulls' commentary
    from virt_table
    union all
    select
      count(*),
      count(val),
      sum(val),
      avg(val),
      sum(val) / count(val),
      sum(val) / count(*),
      'general cleaning of nulls' commentary
    from clear_nulls
  )
select * from compare






Приведу для примера и поведение аналитических функций с пустыми значениями.

with
  -- emulation of test table
  virt_table( id, val ) as (
    select 1, 1 from dual union all
    select 2, 2 from dual union all
    select 3, null from dual union all
    select 4, null from dual union all
    select 5, 5 from dual
  ),
  -- test data without nulls
  clear_nulls as (
    select id, nvl(val, 0) val from virt_table
  ),
  -- for testing analytical functions with nulls
  test( count_rows, count_val, sum_val, avg_val ) as (
    select
      count(*) over (),
      count(val) over (),
      sum(val) over (),
      avg(val) over ()
    from virt_table
    union all
    select
      count(*) over (),
      count(val) over (),
      sum(val) over (),
      avg(val) over ()
    from clear_nulls
  )
select * from test



Для удобства результаты аналитических функций разделены красной линией (верхняя часть - с пустыми значениями, нижняя - без пустых значений). Разница налицо. Поэтому общий вывод таков, необходимо помнить о таких аномалиях и быть очень внимательными с такого рода неопределенного состояния полями. Стоит также отметить, что наличие таких полей в выборках определенных запросов также может приводить к невозможности выполнения последующих подзапросов. Вот один из классических примеров, который можно встретить при работе с иерархическими таблицами. Рассмотрим следующий запрос

with
  -- emulation of test table
  nodes( node, name, parent ) as (
    select 1, 'root', null from dual union all
    select 2, 'node2', 1 from dual union all
    select 3, 'node3', 2 from dual union all
    select 4, 'node4', 3 from dual union all
    select 5, 'node5', 4 from dual
  ),
  -- get path of nodes -- /root/node2/node3/...
  get_nodes_path as (
    select level, sys_connect_by_path ( name, '/' ) path
    from nodes
    connect by prior node = parent
    start with parent is null
  ),
  -- get just root
  get_root as (
    select node, name, parent
    from nodes
    where parent is null
  ),
  -- get just leaf -- wrong variant
  get_leaf_wrong as (
    select node, name, parent
    from nodes
    where node not in (
      select parent
      from nodes
    )
  ),
  -- get just leaf -- correct variant
  get_leaf_correct as (
    select node, name, parent
    from nodes
    where node not in (
      select parent
      from nodes
      where parent is not null
    )
  )
select * from get_nodes_path



Как видно, мы имеем дело с простым деревом. Теперь о классическом примере. Допустим, нам нужно найти все концевые узлы нашего дерева, точнее - листья. В приведенном выше запросе для этого предусмотрены два вложенных представления - get_leaf_wrong и get_leaf_correct. Вроде бы, если обратиться к представлению get_leaf_wrong то мы должны получить ожидаемые листья дерева, но здесь есть нюанс, так как в выборке 

select parent 
from nodes

содержится значение NULL (присущее корневому узлу), которое нельзя сравнивать с другими значениями, на выходе мы получим пустой результат. Если же исключить строку с данным неопределенным значением, что сделано в представлении - get_leaf_correct, тогда будет получен правильный ответ

Всем хорошего дня :)