Commit 32455d3c authored by Kulya's avatar Kulya 😊

n_core_4

parent a92da51d
Pipeline #21 canceled with stages
# Node
node_modules
# bower
bower_components
npm-debug.log
.DS_Store
\ No newline at end of file
# ignore everything
*
# but not these files...
!MultiStreamsMixer.js
!MultiStreamsMixer.min.js
!index.html
!package.json
!bower.json
!server.js
!README.md
\ No newline at end of file
language: node_js
node_js:
- "0.11"
install: npm install
before_script:
- npm install grunt-cli@0.1.13 -g
- npm install grunt@0.4.5
- grunt
after_failure: npm install && grunt
matrix:
fast_finish: true
'use strict';
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt, {
pattern: 'grunt-*',
config: 'package.json',
scope: 'devDependencies'
});
var versionNumber = grunt.file.readJSON('package.json').version;
var banner = '// Last time updated: <%= grunt.template.today("UTC:yyyy-mm-dd h:MM:ss TT Z") %>\n\n';
banner += '// ________________________\n';
banner += '// MultiStreamsMixer v' + versionNumber + '\n\n';
banner += '// Open-Sourced: https://github.com/muaz-khan/MultiStreamsMixer\n\n';
banner += '// --------------------------------------------------\n';
banner += '// Muaz Khan - www.MuazKhan.com\n';
banner += '// MIT License - www.WebRTC-Experiment.com/licence\n';
banner += '// --------------------------------------------------\n\n';
// configure project
grunt.initConfig({
// make node configurations available
pkg: grunt.file.readJSON('package.json'),
concat: {
options: {
stripBanners: true,
separator: '\n',
banner: banner
},
dist: {
src: [
'dev/head.js',
'dev/init.js',
'dev/cross-browser-declarations.js',
'dev/start-drawing-frames.js',
'dev/draw-videos-on-canvas.js',
'dev/get-mixed-stream.js',
'dev/get-mixed-video-stream.js',
'dev/get-mixed-audio-stream.js',
'dev/get-video-element.js',
'dev/append-streams.js',
'dev/release-streams.js',
'dev/replace-streams.js',
'dev/tail.js'
],
dest: 'MultiStreamsMixer.js',
},
},
uglify: {
options: {
mangle: false,
banner: banner
},
my_target: {
files: {
'MultiStreamsMixer.min.js': ['MultiStreamsMixer.js']
}
}
},
jsbeautifier: {
files: ['MultiStreamsMixer.js', 'dev/*.js', 'server.js', 'Gruntfile.js'],
options: {
js: {
braceStyle: "collapse",
breakChainedMethods: false,
e4x: false,
evalCode: false,
indentChar: " ",
indentLevel: 0,
indentSize: 4,
indentWithTabs: false,
jslintHappy: false,
keepArrayIndentation: false,
keepFunctionIndentation: false,
maxPreserveNewlines: 10,
preserveNewlines: true,
spaceBeforeConditional: true,
spaceInParen: false,
unescapeStrings: false,
wrapLineLength: 0
},
html: {
braceStyle: "collapse",
indentChar: " ",
indentScripts: "keep",
indentSize: 4,
maxPreserveNewlines: 10,
preserveNewlines: true,
unformatted: ["a", "sub", "sup", "b", "i", "u"],
wrapLineLength: 0
},
css: {
indentChar: " ",
indentSize: 4
}
}
},
bump: {
options: {
files: ['package.json', 'bower.json'],
updateConfigs: [],
commit: true,
commitMessage: 'v%VERSION%',
commitFiles: ['package.json', 'bower.json'],
createTag: true,
tagName: '%VERSION%',
tagMessage: '%VERSION%',
push: false,
pushTo: 'upstream',
gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
}
},
watch: {
scripts: {
files: ['dev/*.js'],
tasks: ['concat', 'jsbeautifier', 'uglify'],
options: {
spawn: false,
},
}
}
});
// enable plugins
// set default tasks to run when grunt is called without parameters
// http://gruntjs.com/api/grunt.task
grunt.registerTask('default', ['concat', 'jsbeautifier', 'uglify']);
grunt.loadNpmTasks('grunt-contrib-watch');
};
The MIT License (MIT)
Copyright (c) 2017 [Muaz Khan](https://github.com/muaz-khan)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Last time updated: 2019-01-12 7:02:57 AM UTC
// ________________________
// MultiStreamsMixer v1.0.7
// Open-Sourced: https://github.com/muaz-khan/MultiStreamsMixer
// --------------------------------------------------
// Muaz Khan - www.MuazKhan.com
// MIT License - www.WebRTC-Experiment.com/licence
// --------------------------------------------------
function MultiStreamsMixer(arrayOfMediaStreams) {
// requires: chrome://flags/#enable-experimental-web-platform-features
var videos = [];
var isStopDrawingFrames = false;
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.style = 'opacity:0;position:absolute;z-index:-1;top: -100000000;left:-1000000000; margin-top:-1000000000;margin-left:-1000000000;';
(document.body || document.documentElement).appendChild(canvas);
this.disableLogs = false;
this.frameInterval = 10;
this.width = 360;
this.height = 240;
// use gain node to prevent echo
this.useGainNode = true;
var self = this;
// _____________________________
// Cross-Browser-Declarations.js
// WebAudio API representer
var AudioContext = window.AudioContext;
if (typeof AudioContext === 'undefined') {
if (typeof webkitAudioContext !== 'undefined') {
/*global AudioContext:true */
AudioContext = webkitAudioContext;
}
if (typeof mozAudioContext !== 'undefined') {
/*global AudioContext:true */
AudioContext = mozAudioContext;
}
}
/*jshint -W079 */
var URL = window.URL;
if (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') {
/*global URL:true */
URL = webkitURL;
}
if (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator?
if (typeof navigator.webkitGetUserMedia !== 'undefined') {
navigator.getUserMedia = navigator.webkitGetUserMedia;
}
if (typeof navigator.mozGetUserMedia !== 'undefined') {
navigator.getUserMedia = navigator.mozGetUserMedia;
}
}
var MediaStream = window.MediaStream;
if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') {
MediaStream = webkitMediaStream;
}
/*global MediaStream:true */
if (typeof MediaStream !== 'undefined') {
// override "stop" method for all browsers
if (typeof MediaStream.prototype.stop === 'undefined') {
MediaStream.prototype.stop = function() {
this.getTracks().forEach(function(track) {
track.stop();
});
};
}
}
var Storage = {};
if (typeof AudioContext !== 'undefined') {
Storage.AudioContext = AudioContext;
} else if (typeof webkitAudioContext !== 'undefined') {
Storage.AudioContext = webkitAudioContext;
}
function setSrcObject(stream, element) {
if ('srcObject' in element) {
element.srcObject = stream;
} else if ('mozSrcObject' in element) {
element.mozSrcObject = stream;
} else {
element.srcObject = stream;
}
}
this.startDrawingFrames = function() {
drawVideosToCanvas();
};
function drawVideosToCanvas() {
if (isStopDrawingFrames) {
return;
}
var videosLength = videos.length;
var fullcanvas = false;
var remaining = [];
videos.forEach(function(video) {
if (!video.stream) {
video.stream = {};
}
if (video.stream.fullcanvas) {
fullcanvas = video;
} else {
remaining.push(video);
}
});
if (fullcanvas) {
canvas.width = fullcanvas.stream.width;
canvas.height = fullcanvas.stream.height;
} else if (remaining.length) {
canvas.width = videosLength > 1 ? remaining[0].width * 2 : remaining[0].width;
var height = 1;
if (videosLength === 3 || videosLength === 4) {
height = 2;
}
if (videosLength === 5 || videosLength === 6) {
height = 3;
}
if (videosLength === 7 || videosLength === 8) {
height = 4;
}
if (videosLength === 9 || videosLength === 10) {
height = 5;
}
canvas.height = remaining[0].height * height;
} else {
canvas.width = self.width || 360;
canvas.height = self.height || 240;
}
if (fullcanvas && fullcanvas instanceof HTMLVideoElement) {
drawImage(fullcanvas);
}
remaining.forEach(function(video, idx) {
drawImage(video, idx);
});
setTimeout(drawVideosToCanvas, self.frameInterval);
}
function drawImage(video, idx) {
if (isStopDrawingFrames) {
return;
}
var x = 0;
var y = 0;
var width = video.width;
var height = video.height;
if (idx === 1) {
x = video.width;
}
if (idx === 2) {
y = video.height;
}
if (idx === 3) {
x = video.width;
y = video.height;
}
if (idx === 4) {
y = video.height * 2;
}
if (idx === 5) {
x = video.width;
y = video.height * 2;
}
if (idx === 6) {
y = video.height * 3;
}
if (idx === 7) {
x = video.width;
y = video.height * 3;
}
if (typeof video.stream.left !== 'undefined') {
x = video.stream.left;
}
if (typeof video.stream.top !== 'undefined') {
y = video.stream.top;
}
if (typeof video.stream.width !== 'undefined') {
width = video.stream.width;
}
if (typeof video.stream.height !== 'undefined') {
height = video.stream.height;
}
context.drawImage(video, x, y, width, height);
if (typeof video.stream.onRender === 'function') {
video.stream.onRender(context, x, y, width, height, idx);
}
}
function getMixedStream() {
isStopDrawingFrames = false;
var mixedVideoStream = getMixedVideoStream();
var mixedAudioStream = getMixedAudioStream();
if (mixedAudioStream) {
mixedAudioStream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).forEach(function(track) {
mixedVideoStream.addTrack(track);
});
}
var fullcanvas;
arrayOfMediaStreams.forEach(function(stream) {
if (stream.fullcanvas) {
fullcanvas = true;
}
});
return mixedVideoStream;
}
function getMixedVideoStream() {
resetVideoStreams();
var capturedStream;
if ('captureStream' in canvas) {
capturedStream = canvas.captureStream();
} else if ('mozCaptureStream' in canvas) {
capturedStream = canvas.mozCaptureStream();
} else if (!self.disableLogs) {
console.error('Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features');
}
var videoStream = new MediaStream();
capturedStream.getTracks().filter(function(t) {
return t.kind === 'video';
}).forEach(function(track) {
videoStream.addTrack(track);
});
canvas.stream = videoStream;
return videoStream;
}
function getMixedAudioStream() {
// via: @pehrsons
if (!Storage.AudioContextConstructor) {
Storage.AudioContextConstructor = new Storage.AudioContext();
}
self.audioContext = Storage.AudioContextConstructor;
self.audioSources = [];
if (self.useGainNode === true) {
self.gainNode = self.audioContext.createGain();
self.gainNode.connect(self.audioContext.destination);
self.gainNode.gain.value = 0; // don't hear self
}
var audioTracksLength = 0;
arrayOfMediaStreams.forEach(function(stream) {
if (!stream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).length) {
return;
}
audioTracksLength++;
var audioSource = self.audioContext.createMediaStreamSource(stream);
if (self.useGainNode === true) {
audioSource.connect(self.gainNode);
}
self.audioSources.push(audioSource);
});
if (!audioTracksLength) {
return;
}
self.audioDestination = self.audioContext.createMediaStreamDestination();
self.audioSources.forEach(function(audioSource) {
audioSource.connect(self.audioDestination);
});
return self.audioDestination.stream;
}
function getVideo(stream) {
var video = document.createElement('video');
setSrcObject(stream, video);
video.muted = true;
video.volume = 0;
video.width = stream.width || self.width || 360;
video.height = stream.height || self.height || 240;
video.play();
return video;
}
this.appendStreams = function(streams) {
if (!streams) {
throw 'First parameter is required.';
}
if (!(streams instanceof Array)) {
streams = [streams];
}
arrayOfMediaStreams.concat(streams);
streams.forEach(function(stream) {
if (stream.getTracks().filter(function(t) {
return t.kind === 'video';
}).length) {
var video = getVideo(stream);
video.stream = stream;
videos.push(video);
}
if (stream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).length && self.audioContext) {
var audioSource = self.audioContext.createMediaStreamSource(stream);
audioSource.connect(self.audioDestination);
self.audioSources.push(audioSource);
}
});
};
this.releaseStreams = function() {
videos = [];
isStopDrawingFrames = true;
if (self.gainNode) {
self.gainNode.disconnect();
self.gainNode = null;
}
if (self.audioSources.length) {
self.audioSources.forEach(function(source) {
source.disconnect();
});
self.audioSources = [];
}
if (self.audioDestination) {
self.audioDestination.disconnect();
self.audioDestination = null;
}
if (self.audioContext) {
self.audioContext.close();
}
self.audioContext = null;
context.clearRect(0, 0, canvas.width, canvas.height);
if (canvas.stream) {
canvas.stream.stop();
canvas.stream = null;
}
};
this.resetVideoStreams = function(streams) {
if (streams && !(streams instanceof Array)) {
streams = [streams];
}
resetVideoStreams(streams);
};
function resetVideoStreams(streams) {
videos = [];
streams = streams || arrayOfMediaStreams;
// via: @adrian-ber
streams.forEach(function(stream) {
if (!stream.getTracks().filter(function(t) {
return t.kind === 'video';
}).length) {
return;
}
var video = getVideo(stream);
video.stream = stream;
videos.push(video);
});
}
// for debugging
this.name = 'MultiStreamsMixer';
this.toString = function() {
return this.name;
};
this.getMixedStream = getMixedStream;
}
// Last time updated: 2019-01-12 7:02:57 AM UTC
// ________________________
// MultiStreamsMixer v1.0.7
// Open-Sourced: https://github.com/muaz-khan/MultiStreamsMixer
// --------------------------------------------------
// Muaz Khan - www.MuazKhan.com
// MIT License - www.WebRTC-Experiment.com/licence
// --------------------------------------------------
function MultiStreamsMixer(arrayOfMediaStreams){function setSrcObject(stream,element){"srcObject"in element?element.srcObject=stream:"mozSrcObject"in element?element.mozSrcObject=stream:element.srcObject=stream}function drawVideosToCanvas(){if(!isStopDrawingFrames){var videosLength=videos.length,fullcanvas=!1,remaining=[];if(videos.forEach(function(video){video.stream||(video.stream={}),video.stream.fullcanvas?fullcanvas=video:remaining.push(video)}),fullcanvas)canvas.width=fullcanvas.stream.width,canvas.height=fullcanvas.stream.height;else if(remaining.length){canvas.width=videosLength>1?2*remaining[0].width:remaining[0].width;var height=1;3!==videosLength&&4!==videosLength||(height=2),5!==videosLength&&6!==videosLength||(height=3),7!==videosLength&&8!==videosLength||(height=4),9!==videosLength&&10!==videosLength||(height=5),canvas.height=remaining[0].height*height}else canvas.width=self.width||360,canvas.height=self.height||240;fullcanvas&&fullcanvas instanceof HTMLVideoElement&&drawImage(fullcanvas),remaining.forEach(function(video,idx){drawImage(video,idx)}),setTimeout(drawVideosToCanvas,self.frameInterval)}}function drawImage(video,idx){if(!isStopDrawingFrames){var x=0,y=0,width=video.width,height=video.height;1===idx&&(x=video.width),2===idx&&(y=video.height),3===idx&&(x=video.width,y=video.height),4===idx&&(y=2*video.height),5===idx&&(x=video.width,y=2*video.height),6===idx&&(y=3*video.height),7===idx&&(x=video.width,y=3*video.height),"undefined"!=typeof video.stream.left&&(x=video.stream.left),"undefined"!=typeof video.stream.top&&(y=video.stream.top),"undefined"!=typeof video.stream.width&&(width=video.stream.width),"undefined"!=typeof video.stream.height&&(height=video.stream.height),context.drawImage(video,x,y,width,height),"function"==typeof video.stream.onRender&&video.stream.onRender(context,x,y,width,height,idx)}}function getMixedStream(){isStopDrawingFrames=!1;var mixedVideoStream=getMixedVideoStream(),mixedAudioStream=getMixedAudioStream();mixedAudioStream&&mixedAudioStream.getTracks().filter(function(t){return"audio"===t.kind}).forEach(function(track){mixedVideoStream.addTrack(track)});var fullcanvas;return arrayOfMediaStreams.forEach(function(stream){stream.fullcanvas&&(fullcanvas=!0)}),mixedVideoStream}function getMixedVideoStream(){resetVideoStreams();var capturedStream;"captureStream"in canvas?capturedStream=canvas.captureStream():"mozCaptureStream"in canvas?capturedStream=canvas.mozCaptureStream():self.disableLogs||console.error("Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features");var videoStream=new MediaStream;return capturedStream.getTracks().filter(function(t){return"video"===t.kind}).forEach(function(track){videoStream.addTrack(track)}),canvas.stream=videoStream,videoStream}function getMixedAudioStream(){Storage.AudioContextConstructor||(Storage.AudioContextConstructor=new Storage.AudioContext),self.audioContext=Storage.AudioContextConstructor,self.audioSources=[],self.useGainNode===!0&&(self.gainNode=self.audioContext.createGain(),self.gainNode.connect(self.audioContext.destination),self.gainNode.gain.value=0);var audioTracksLength=0;if(arrayOfMediaStreams.forEach(function(stream){if(stream.getTracks().filter(function(t){return"audio"===t.kind}).length){audioTracksLength++;var audioSource=self.audioContext.createMediaStreamSource(stream);self.useGainNode===!0&&audioSource.connect(self.gainNode),self.audioSources.push(audioSource)}}),audioTracksLength)return self.audioDestination=self.audioContext.createMediaStreamDestination(),self.audioSources.forEach(function(audioSource){audioSource.connect(self.audioDestination)}),self.audioDestination.stream}function getVideo(stream){var video=document.createElement("video");return setSrcObject(stream,video),video.muted=!0,video.volume=0,video.width=stream.width||self.width||360,video.height=stream.height||self.height||240,video.play(),video}function resetVideoStreams(streams){videos=[],streams=streams||arrayOfMediaStreams,streams.forEach(function(stream){if(stream.getTracks().filter(function(t){return"video"===t.kind}).length){var video=getVideo(stream);video.stream=stream,videos.push(video)}})}var videos=[],isStopDrawingFrames=!1,canvas=document.createElement("canvas"),context=canvas.getContext("2d");canvas.style="opacity:0;position:absolute;z-index:-1;top: -100000000;left:-1000000000; margin-top:-1000000000;margin-left:-1000000000;",(document.body||document.documentElement).appendChild(canvas),this.disableLogs=!1,this.frameInterval=10,this.width=360,this.height=240,this.useGainNode=!0;var self=this,AudioContext=window.AudioContext;"undefined"==typeof AudioContext&&("undefined"!=typeof webkitAudioContext&&(AudioContext=webkitAudioContext),"undefined"!=typeof mozAudioContext&&(AudioContext=mozAudioContext));var URL=window.URL;"undefined"==typeof URL&&"undefined"!=typeof webkitURL&&(URL=webkitURL),"undefined"!=typeof navigator&&"undefined"==typeof navigator.getUserMedia&&("undefined"!=typeof navigator.webkitGetUserMedia&&(navigator.getUserMedia=navigator.webkitGetUserMedia),"undefined"!=typeof navigator.mozGetUserMedia&&(navigator.getUserMedia=navigator.mozGetUserMedia));var MediaStream=window.MediaStream;"undefined"==typeof MediaStream&&"undefined"!=typeof webkitMediaStream&&(MediaStream=webkitMediaStream),"undefined"!=typeof MediaStream&&"undefined"==typeof MediaStream.prototype.stop&&(MediaStream.prototype.stop=function(){this.getTracks().forEach(function(track){track.stop()})});var Storage={};"undefined"!=typeof AudioContext?Storage.AudioContext=AudioContext:"undefined"!=typeof webkitAudioContext&&(Storage.AudioContext=webkitAudioContext),this.startDrawingFrames=function(){drawVideosToCanvas()},this.appendStreams=function(streams){if(!streams)throw"First parameter is required.";streams instanceof Array||(streams=[streams]),arrayOfMediaStreams.concat(streams),streams.forEach(function(stream){if(stream.getTracks().filter(function(t){return"video"===t.kind}).length){var video=getVideo(stream);video.stream=stream,videos.push(video)}if(stream.getTracks().filter(function(t){return"audio"===t.kind}).length&&self.audioContext){var audioSource=self.audioContext.createMediaStreamSource(stream);audioSource.connect(self.audioDestination),self.audioSources.push(audioSource)}})},this.releaseStreams=function(){videos=[],isStopDrawingFrames=!0,self.gainNode&&(self.gainNode.disconnect(),self.gainNode=null),self.audioSources.length&&(self.audioSources.forEach(function(source){source.disconnect()}),self.audioSources=[]),self.audioDestination&&(self.audioDestination.disconnect(),self.audioDestination=null),self.audioContext&&self.audioContext.close(),self.audioContext=null,context.clearRect(0,0,canvas.width,canvas.height),canvas.stream&&(canvas.stream.stop(),canvas.stream=null)},this.resetVideoStreams=function(streams){!streams||streams instanceof Array||(streams=[streams]),resetVideoStreams(streams)},this.name="MultiStreamsMixer",this.toString=function(){return this.name},this.getMixedStream=getMixedStream}
\ No newline at end of file
// @maalouf
export class MultiStreamsMixer {
videos : Array<any>;
isStopDrawingFrames: boolean;
canvas : any;
context : CanvasRenderingContext2D;
disableLogs: boolean;
frameInterval: number;
width : number;
height: number;
useGainNode : boolean;
arrayOfMediaStreams: Array<MediaStream>;
/********************************************/
audioContext : any;
audioDestination : any;
audioSources : Array<any>;
gainNode : GainNode;
constructor (_arrayOfMediaStreams) {
// requires: chrome://flags/#enable-experimental-web-platform-features
this.arrayOfMediaStreams = _arrayOfMediaStreams;
this.videos = new Array<any>();
this.isStopDrawingFrames = false;
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
// this.canvas.style = 'opacity:0;position:absolute;z-index:-1;top: -100000000;left:-1000000000; margin-top:-1000000000;margin-left:-1000000000;';
// (document.body || document.documentElement).appendChild(canvas);
this.disableLogs = false;
this.frameInterval = 10;
this.width = 360;
this.height = 240;
this.useGainNode = true;
this.audioContext = undefined;
}
private isPureAudio(){
for (let i = 0; i < this.arrayOfMediaStreams.length;i++){
if (this.arrayOfMediaStreams[i].getTracks().filter(function(t) {
return t.kind === 'video';
}).length > 0) return false;
}
return true;
}
getAudioContext():AudioContext {
if (typeof AudioContext !== 'undefined') {
return new AudioContext();
} else if (typeof (<any>window).webkitAudioContext !== 'undefined') {
return new (<any>window).webkitAudioContext();
} else if (typeof (<any>window).mozAudioContext !== 'undefined') {
return new (<any>window).mozAudioContext();
}
}
/**************************************************/
private setSrcObject(stream, element) {
var URL = window.URL || (<any>window).webkitURL;
if ('srcObject' in element) {
element.srcObject = stream;
} else if ('mozSrcObject' in element) {
element.mozSrcObject = stream;
} else if ('createObjectURL' in URL) {
element.src = URL.createObjectURL(stream);
} else {
alert('createObjectURL/srcObject both are not supported.');
}
}
public startDrawingFrames() {
this.drawVideosToCanvas();
};
private drawVideosToCanvas() {
if (this.isStopDrawingFrames) {
return;
}
let videosLength = this.videos.length;
let fullcanvas = undefined;
let remaining = [];
this.videos.forEach(video => {
if (!video.stream) {
video.stream = {};
}
if (video.stream.fullcanvas) {
fullcanvas = video;
} else {
remaining.push(video);
}
});
if (fullcanvas !== undefined) {
this.canvas.width = fullcanvas.stream.width;
this.canvas.height = fullcanvas.stream.height;
} else if (remaining.length) {
this.canvas.width = videosLength > 1 ? remaining[0].width * 2 : remaining[0].width;
var height = 1;
if (videosLength === 3 || videosLength === 4) {
height = 2;
}
if (videosLength === 5 || videosLength === 6) {
height = 3;
}
if (videosLength === 7 || videosLength === 8) {
height = 4;
}
if (videosLength === 9 || videosLength === 10) {
height = 5;
}
this.canvas.height = remaining[0].height * height;
} else {
this.canvas.width = this.width || 360;
this.canvas.height = this.height || 240;
}
if (fullcanvas && fullcanvas instanceof HTMLVideoElement) {
this.drawImage(fullcanvas,0);
}
remaining.forEach((video, idx) => {
this.drawImage(video, idx);
});
setTimeout(this.drawVideosToCanvas.bind(this), this.frameInterval);
}
private drawImage(video, idx) {
if (this.isStopDrawingFrames) {
return;
}
var x = 0;
var y = 0;
var width = video.width;
var height = video.height;
if (idx === 1) {
x = video.width;
}
if (idx === 2) {
y = video.height;
}
if (idx === 3) {
x = video.width;
y = video.height;
}
if (idx === 4) {
y = video.height * 2;
}
if (idx === 5) {
x = video.width;
y = video.height * 2;
}
if (idx === 6) {
y = video.height * 3;
}
if (idx === 7) {
x = video.width;
y = video.height * 3;
}
if (typeof video.stream.left !== 'undefined') {
x = video.stream.left;
}
if (typeof video.stream.top !== 'undefined') {
y = video.stream.top;
}
if (typeof video.stream.width !== 'undefined') {
width = video.stream.width;
}
if (typeof video.stream.height !== 'undefined') {
height = video.stream.height;
}
this.context.drawImage(video, x, y, width, height);
if (typeof video.stream.onRender === 'function') {
video.stream.onRender(this.context, x, y, width, height, idx);
}
}
getMixedStream() {
this.isStopDrawingFrames = false;
let mixedAudioStream = this.getMixedAudioStream();
let mixedVideoStream = (this.isPureAudio()) ? undefined: this.getMixedVideoStream();
if (mixedVideoStream == undefined){
return mixedAudioStream;
} else {
if (mixedAudioStream) {
mixedAudioStream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).forEach(track => {
mixedVideoStream.addTrack(track);
});
}
return mixedVideoStream;
}
}
private getMixedVideoStream() {
this.resetVideoStreams();
var capturedStream = this.canvas.captureStream() || this.canvas.mozCaptureStream();
var videoStream = new MediaStream();
capturedStream.getTracks().filter(function(t) {
return t.kind === 'video';
}).forEach(track => {
videoStream.addTrack(track);
});
this.canvas.stream = videoStream;
return videoStream;
}
private getMixedAudioStream() {
// via: @pehrsons
if (this.audioContext == undefined) this.audioContext = this.getAudioContext();
this.audioSources = new Array<any>();
if (this.useGainNode === true) {
this.gainNode = this.audioContext.createGain();
this.gainNode.connect(this.audioContext.destination);
this.gainNode.gain.value = 0; // don't hear self
}
let audioTracksLength = 0;
this.arrayOfMediaStreams.forEach(stream => {
if (!stream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).length) {
return;
}
audioTracksLength++;
let _audioSource = this.audioContext.createMediaStreamSource(stream);
if (this.useGainNode === true) {
_audioSource.connect(this.gainNode);
}
this.audioSources.push(_audioSource);
});
if (!audioTracksLength) {
return undefined;
}
this.audioDestination = this.audioContext.createMediaStreamDestination();
this.audioSources.forEach(_audioSource => {
_audioSource.connect(this.audioDestination);
});
return this.audioDestination.stream;
}
private getVideo(stream) {
var video = document.createElement('video');
this.setSrcObject(stream, video);
video.muted = true;
video.volume = 0;
video.width = stream.width || this.width || 360;
video.height = stream.height || this.height || 240;
video.play();
return video;
}
appendStreams(streams) {
if (!streams) {
throw 'First parameter is required.';
}
if (!(streams instanceof Array)) {
streams = [streams];
}
this.arrayOfMediaStreams.concat(streams);
streams.forEach(stream => {
if (stream.getTracks().filter(function(t) {
return t.kind === 'video';
}).length) {
var video = this.getVideo(stream);
video['stream'] = stream;
this.videos.push(video);
}
if (stream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).length && this.audioContext) {
var audioSource = this.audioContext.createMediaStreamSource(stream);
audioSource.connect(this.audioDestination);
this.audioSources.push(audioSource);
}
});
};
private releaseStreams() {
this.videos = [];
this.isStopDrawingFrames = true;
if (this.gainNode) {
this.gainNode.disconnect();
this.gainNode = null;
}
if (this.audioSources.length) {
this.audioSources.forEach(source => {
source.disconnect();
});
this.audioSources = [];
}
if (this.audioDestination) {
this.audioDestination.disconnect();
this.audioDestination = null;
}
if (this.audioContext) {
this.audioContext.close();
}
this.audioContext = null;
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
if (this.canvas.stream) {
this.canvas.stream.stop();
this.canvas.stream = null;
}
}
private resetVideoStreams(streams?:any) {
if (streams && !(streams instanceof Array)) {
streams = [streams];
}
this._resetVideoStreams(streams);
}
private _resetVideoStreams(streams) {
this.videos = [];
streams = streams || this.arrayOfMediaStreams;
// via: @adrian-ber
streams.forEach(stream => {
if (!stream.getTracks().filter(function(t) {
return t.kind === 'video';
}).length) {
return;
}
let tempVideo = this.getVideo(stream);
tempVideo['stream'] = stream;
this.videos.push(tempVideo);
});
}
}
# [MultiStreamsMixer.js](https://github.com/muaz-khan/MultiStreamsMixer) | [LIVE DEMO](https://www.webrtc-experiment.com/MultiStreamsMixer/)
* Mix Multiple Cameras or Videos
* Mix Multiple Microphones or Audios (Mp3/Wav/Ogg)
* Mix Multiple Screens or Screen+Video
* Mix Canvas 2D Animation + Camera + Screen
* and **GET SINGLE STREAM!!**
[![npm](https://img.shields.io/npm/v/multistreamsmixer.svg)](https://npmjs.org/package/multistreamsmixer) [![downloads](https://img.shields.io/npm/dm/multistreamsmixer.svg)](https://npmjs.org/package/multistreamsmixer) [![Build Status: Linux](https://travis-ci.org/muaz-khan/MultiStreamsMixer.png?branch=master)](https://travis-ci.org/muaz-khan/MultiStreamsMixer)
# All Demos
1. **Main Demo:** https://www.webrtc-experiment.com/MultiStreamsMixer/
2. [Record Multiple Cameras](https://www.webrtc-experiment.com/RecordRTC/simple-demos/multi-cameras-recording.html)
3. [Record Camera+Screen](https://www.webrtc-experiment.com/RecordRTC/simple-demos/video-plus-screen-recording.html)
> Pass multiple streams (e.g. screen+camera or multiple-cameras) and get single stream.
# Link the library
```html
<script src="https://cdn.webrtc-experiment.com/MultiStreamsMixer.js"></script>
<!-- or min.js -->
<script src="https://cdn.webrtc-experiment.com/MultiStreamsMixer.min.js"></script>
<!-- or without CDN -->
<script src="https://www.webrtc-experiment.com/MultiStreamsMixer.js"></script>
<!-- or rawgit -->
<script src="https://rawgit.com/muaz-khan/MultiStreamsMixer/master/MultiStreamsMixer.js"></script>
```
Or link specific build:
* https://github.com/muaz-khan/MultiStreamsMixer/releases
```html
<script src="https://github.com/muaz-khan/MultiStreamsMixer/releases/download/1.0.4/MultiStreamsMixer.js"></script>
```
Or install using NPM:
```sh
npm install multistreamsmixer
```
# How to mix audios?
```javascript
var audioMixer = new MultiStreamsMixer([microphone1, microphone2]);
// record using MediaRecorder API
var recorder = new MediaRecorder(audioMixer.getMixedStream());
// or share using WebRTC
rtcPeerConnection.addStream(audioMixer.getMixedStream());
```
# How to mix screen+camera?
```javascript
screenStream.fullcanvas = true;
screenStream.width = screen.width; // or 3840
screenStream.height = screen.height; // or 2160
cameraStream.width = parseInt((20 / 100) * screenStream.width);
cameraStream.height = parseInt((20 / 100) * screenStream.height);
cameraStream.top = screenStream.height - cameraStream.height;
cameraStream.left = screenStream.width - cameraStream.width;
var mixer = new MultiStreamsMixer([screenStream, cameraStream]);
rtcPeerConnection.addStream(audioMixer.getMixedStream());
mixer.frameInterval = 1;
mixer.startDrawingFrames();
btnStopStreams.onclick = function() {
mixer.releaseStreams();
};
btnAppendNewStreams.onclick = function() {
mixer.appendStreams([anotherStream]);
};
btnStopScreenSharing.onclick = function() {
// replace all old streams with this one
// it will replace only video tracks
mixer.resetVideoStreams([cameraStreamOnly]);
};
```
# How to mix multiple cameras?
```javascript
var mixer = new MultiStreamsMixer([camera1, camera2]);
rtcPeerConnection.addStream(audioMixer.getMixedStream());
mixer.frameInterval = 1;
mixer.startDrawingFrames();
```
# API
1. `getMixedStream`: (function) returns mixed MediaStream object
2. `frameInterval`: (property) allows you set frame interval
3. `startDrawingFrames`: (function) start mixing video streams
4. `resetVideoStreams`: (function) replace all existing video streams with new ones
5. `releaseStreams`: (function) stop mixing streams
6. `appendStreams`: (function) append extra/new streams (anytime)
# TypeScript / Angular
```javascript
import {MultiStreamsMixer} from 'yourPath/MultiStreamsMixer';
use normally ex:
let mixer = new MultiStreamsMixer([stream1,stream2]);
mixer.appendStreams(stream3);
let mixed = mixer.getMixedStream();
```
P.S: pollyfills are removed (except for AudioContext) use adapter instead
## License
[MultiStreamsMixer.js](https://github.com/muaz-khan/MultiStreamsMixer) is released under [MIT licence](https://www.webrtc-experiment.com/licence/) . Copyright (c) [Muaz Khan](http://www.MuazKhan.com).
{
"name": "multistreamsmixer",
"description": "Pass multiple streams (e.g. screen+camera or multiple-cameras) and get single stream.",
"version": "1.0.7",
"authors": [
{
"name": "Muaz Khan",
"email": "muazkh@gmail.com",
"homepage": "https://muazkhan.com/"
}
],
"main": "./MultiStreamsMixer.js",
"keywords": [
"webrtc",
"multistreamsmixer",
"webrtc-library",
"library",
"javascript",
"rtcweb",
"webrtc-experiment",
"javascript-library",
"muaz",
"muaz-khan"
],
"repository": {
"type": "git",
"url": "https://github.com/muaz-khan/MultiStreamsMixer.git"
},
"homepage": "https://www.webrtc-experiment.com/MultiStreamsMixer/",
"ignore": [
"**/.*",
"node_modules",
"test",
"tests"
]
}
# MultiStreamsMixer | Mix Multiple Cameras & Screens into Single Stream
MultiStreamsMixer.js is separated/splitted into unique files.
This directory contains all those development files.
`grunt` tools are used to concatenate/merge all these files into `~/MultiStreamsMixer.js`.
## License
[MultiStreamsMixer.js](https://github.com/muaz-khan/MultiStreamsMixer) is released under [MIT licence](https://www.webrtc-experiment.com/licence/) . Copyright (c) [Muaz Khan](http://www.MuazKhan.com/).
this.appendStreams = function(streams) {
if (!streams) {
throw 'First parameter is required.';
}
if (!(streams instanceof Array)) {
streams = [streams];
}
arrayOfMediaStreams.concat(streams);
streams.forEach(function(stream) {
if (stream.getTracks().filter(function(t) {
return t.kind === 'video';
}).length) {
var video = getVideo(stream);
video.stream = stream;
videos.push(video);
}
if (stream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).length && self.audioContext) {
var audioSource = self.audioContext.createMediaStreamSource(stream);
audioSource.connect(self.audioDestination);
self.audioSources.push(audioSource);
}
});
};
// _____________________________
// Cross-Browser-Declarations.js
// WebAudio API representer
var AudioContext = window.AudioContext;
if (typeof AudioContext === 'undefined') {
if (typeof webkitAudioContext !== 'undefined') {
/*global AudioContext:true */
AudioContext = webkitAudioContext;
}
if (typeof mozAudioContext !== 'undefined') {
/*global AudioContext:true */
AudioContext = mozAudioContext;
}
}
/*jshint -W079 */
var URL = window.URL;
if (typeof URL === 'undefined' && typeof webkitURL !== 'undefined') {
/*global URL:true */
URL = webkitURL;
}
if (typeof navigator !== 'undefined' && typeof navigator.getUserMedia === 'undefined') { // maybe window.navigator?
if (typeof navigator.webkitGetUserMedia !== 'undefined') {
navigator.getUserMedia = navigator.webkitGetUserMedia;
}
if (typeof navigator.mozGetUserMedia !== 'undefined') {
navigator.getUserMedia = navigator.mozGetUserMedia;
}
}
var MediaStream = window.MediaStream;
if (typeof MediaStream === 'undefined' && typeof webkitMediaStream !== 'undefined') {
MediaStream = webkitMediaStream;
}
/*global MediaStream:true */
if (typeof MediaStream !== 'undefined') {
// override "stop" method for all browsers
if (typeof MediaStream.prototype.stop === 'undefined') {
MediaStream.prototype.stop = function() {
this.getTracks().forEach(function(track) {
track.stop();
});
};
}
}
var Storage = {};
if (typeof AudioContext !== 'undefined') {
Storage.AudioContext = AudioContext;
} else if (typeof webkitAudioContext !== 'undefined') {
Storage.AudioContext = webkitAudioContext;
}
function setSrcObject(stream, element) {
if ('srcObject' in element) {
element.srcObject = stream;
} else if ('mozSrcObject' in element) {
element.mozSrcObject = stream;
} else {
element.srcObject = stream;
}
}
function drawVideosToCanvas() {
if (isStopDrawingFrames) {
return;
}
var videosLength = videos.length;
var fullcanvas = false;
var remaining = [];
videos.forEach(function(video) {
if (!video.stream) {
video.stream = {};
}
if (video.stream.fullcanvas) {
fullcanvas = video;
} else {
remaining.push(video);
}
});
if (fullcanvas) {
canvas.width = fullcanvas.stream.width;
canvas.height = fullcanvas.stream.height;
} else if (remaining.length) {
canvas.width = videosLength > 1 ? remaining[0].width * 2 : remaining[0].width;
var height = 1;
if (videosLength === 3 || videosLength === 4) {
height = 2;
}
if (videosLength === 5 || videosLength === 6) {
height = 3;
}
if (videosLength === 7 || videosLength === 8) {
height = 4;
}
if (videosLength === 9 || videosLength === 10) {
height = 5;
}
canvas.height = remaining[0].height * height;
} else {
canvas.width = self.width || 360;
canvas.height = self.height || 240;
}
if (fullcanvas && fullcanvas instanceof HTMLVideoElement) {
drawImage(fullcanvas);
}
remaining.forEach(function(video, idx) {
drawImage(video, idx);
});
setTimeout(drawVideosToCanvas, self.frameInterval);
}
function drawImage(video, idx) {
if (isStopDrawingFrames) {
return;
}
var x = 0;
var y = 0;
var width = video.width;
var height = video.height;
if (idx === 1) {
x = video.width;
}
if (idx === 2) {
y = video.height;
}
if (idx === 3) {
x = video.width;
y = video.height;
}
if (idx === 4) {
y = video.height * 2;
}
if (idx === 5) {
x = video.width;
y = video.height * 2;
}
if (idx === 6) {
y = video.height * 3;
}
if (idx === 7) {
x = video.width;
y = video.height * 3;
}
if (typeof video.stream.left !== 'undefined') {
x = video.stream.left;
}
if (typeof video.stream.top !== 'undefined') {
y = video.stream.top;
}
if (typeof video.stream.width !== 'undefined') {
width = video.stream.width;
}
if (typeof video.stream.height !== 'undefined') {
height = video.stream.height;
}
context.drawImage(video, x, y, width, height);
if (typeof video.stream.onRender === 'function') {
video.stream.onRender(context, x, y, width, height, idx);
}
}
function getMixedAudioStream() {
// via: @pehrsons
if (!Storage.AudioContextConstructor) {
Storage.AudioContextConstructor = new Storage.AudioContext();
}
self.audioContext = Storage.AudioContextConstructor;
self.audioSources = [];
if (self.useGainNode === true) {
self.gainNode = self.audioContext.createGain();
self.gainNode.connect(self.audioContext.destination);
self.gainNode.gain.value = 0; // don't hear self
}
var audioTracksLength = 0;
arrayOfMediaStreams.forEach(function(stream) {
if (!stream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).length) {
return;
}
audioTracksLength++;
var audioSource = self.audioContext.createMediaStreamSource(stream);
if (self.useGainNode === true) {
audioSource.connect(self.gainNode);
}
self.audioSources.push(audioSource);
});
if (!audioTracksLength) {
return;
}
self.audioDestination = self.audioContext.createMediaStreamDestination();
self.audioSources.forEach(function(audioSource) {
audioSource.connect(self.audioDestination);
});
return self.audioDestination.stream;
}
function getMixedStream() {
isStopDrawingFrames = false;
var mixedVideoStream = getMixedVideoStream();
var mixedAudioStream = getMixedAudioStream();
if (mixedAudioStream) {
mixedAudioStream.getTracks().filter(function(t) {
return t.kind === 'audio';
}).forEach(function(track) {
mixedVideoStream.addTrack(track);
});
}
var fullcanvas;
arrayOfMediaStreams.forEach(function(stream) {
if (stream.fullcanvas) {
fullcanvas = true;
}
});
return mixedVideoStream;
}
function getMixedVideoStream() {
resetVideoStreams();
var capturedStream;
if ('captureStream' in canvas) {
capturedStream = canvas.captureStream();
} else if ('mozCaptureStream' in canvas) {
capturedStream = canvas.mozCaptureStream();
} else if (!self.disableLogs) {
console.error('Upgrade to latest Chrome or otherwise enable this flag: chrome://flags/#enable-experimental-web-platform-features');
}
var videoStream = new MediaStream();
capturedStream.getTracks().filter(function(t) {
return t.kind === 'video';
}).forEach(function(track) {
videoStream.addTrack(track);
});
canvas.stream = videoStream;
return videoStream;
}
function getVideo(stream) {
var video = document.createElement('video');
setSrcObject(stream, video);
video.muted = true;
video.volume = 0;
video.width = stream.width || self.width || 360;
video.height = stream.height || self.height || 240;
video.play();
return video;
}
function MultiStreamsMixer(arrayOfMediaStreams) {
// requires: chrome://flags/#enable-experimental-web-platform-features
var videos = [];
var isStopDrawingFrames = false;
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.style = 'opacity:0;position:absolute;z-index:-1;top: -100000000;left:-1000000000; margin-top:-1000000000;margin-left:-1000000000;';
(document.body || document.documentElement).appendChild(canvas);
this.disableLogs = false;
this.frameInterval = 10;
this.width = 360;
this.height = 240;
// use gain node to prevent echo
this.useGainNode = true;
var self = this;
if (typeof module !== 'undefined' /* && !!module.exports*/ ) {
module.exports = MultiStreamsMixer;
}
this.releaseStreams = function() {
videos = [];
isStopDrawingFrames = true;
if (self.gainNode) {
self.gainNode.disconnect();
self.gainNode = null;
}
if (self.audioSources.length) {
self.audioSources.forEach(function(source) {
source.disconnect();
});
self.audioSources = [];
}
if (self.audioDestination) {
self.audioDestination.disconnect();
self.audioDestination = null;
}
if (self.audioContext) {
self.audioContext.close();
}
self.audioContext = null;
context.clearRect(0, 0, canvas.width, canvas.height);
if (canvas.stream) {
canvas.stream.stop();
canvas.stream = null;
}
};
this.resetVideoStreams = function(streams) {
if (streams && !(streams instanceof Array)) {
streams = [streams];
}
resetVideoStreams(streams);
};
function resetVideoStreams(streams) {
videos = [];
streams = streams || arrayOfMediaStreams;
// via: @adrian-ber
streams.forEach(function(stream) {
if (!stream.getTracks().filter(function(t) {
return t.kind === 'video';
}).length) {
return;
}
var video = getVideo(stream);
video.stream = stream;
videos.push(video);
});
}
this.startDrawingFrames = function() {
drawVideosToCanvas();
};
// for debugging
this.name = 'MultiStreamsMixer';
this.toString = function() {
return this.name;
};
this.getMixedStream = getMixedStream;
}
<script>window.demoVersion = '2019.01.14';</script>
<!--
> Muaz Khan - www.MuazKhan.com
> MIT License - www.WebRTC-Experiment.com/licence
> Documentation - github.com/muaz-khan/MultiStreamsMixer
-->
<!DOCTYPE html>
<html lang="en">
<head>
<title>MultiStreamsMixer | Mix Multiple Cameras & Screens into Single Stream</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="author" type="text/html" href="https://plus.google.com/+MuazKhan">
<meta name="author" content="Muaz Khan">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="stylesheet" href="https://cdn.webrtc-experiment.com/style.css">
<style>
h1 span {
background: yellow;
border: 2px solid #8e1515;
padding: 2px 8px;
margin: 2px 5px;
border-radius: 7px;
color: #8e1515;
display: inline-block;
}
video {
max-width: 100%;
border-radius: 5px;
border: 1px solid black;
padding: 2px;
}
</style>
<script src="https://cdn.webrtc-experiment.com/MultiStreamsMixer.js"></script>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="https://cdn.webrtc-experiment.com/getScreenId.js"> </script>
<script src="https://cdn.webrtc-experiment.com/FileSelector.js"></script>
<script src="https://cdn.webrtc-experiment.com/RecordRTC.js"></script>
</head>
<body>
<article>
<header style="text-align: center;">
<h1>
MultiStreamsMixer | Mix Multiple Cameras & <br>Screens into Single Stream
</h1>
<p style="margin:0;">
<a href="https://www.webrtc-experiment.com/">HOME</a>
<span> &copy; </span>
<a href="http://www.MuazKhan.com/" target="_blank">Muaz Khan</a> .
<a href="http://twitter.com/WebRTCWeb" target="_blank" title="Twitter profile for WebRTC Experiments">@WebRTCWeb</a> .
<a href="https://github.com/muaz-khan?tab=repositories" target="_blank" title="Github Profile">Github</a> .
<a href="https://github.com/muaz-khan/MultiStreamsMixer/issues?state=open" target="_blank">Latest issues</a> .
<a href="https://github.com/muaz-khan/MultiStreamsMixer/commits/master" target="_blank">What's New?</a>
</p>
</header>
<div class="github-stargazers"></div>
<section style="text-align: center; margin-top: 15px; color: red;" id="demoVersion"></section>
<script>var date=new Date(window.demoVersion),month=date.toLocaleString("en-us",{month:"long"}),day=date.getUTCDate();day.toString().length<=9&&(day=day.toString().length == 1 ? "0"+day : day);var year=date.getUTCFullYear(); document.getElementById("demoVersion").innerHTML="Last Updated On: <time>"+month+" "+day+" "+year+"</time>";</script>
<div style="text-align:center;">
<a href="https://www.npmjs.com/package/multistreamsmixer" target="_blank">
<img src="https://img.shields.io/npm/v/multistreamsmixer.svg">
</a>
<a href="https://www.npmjs.com/package/multistreamsmixer" target="_blank">
<img src="https://img.shields.io/npm/dm/multistreamsmixer.svg">
</a>
<a href="https://travis-ci.org/muaz-khan/MultiStreamsMixer">
<img src="https://travis-ci.org/muaz-khan/MultiStreamsMixer.png?branch=master">
</a>
</div>
<section class="experiment" style="text-align: center;">
<button id="btn-get-mixed-stream">Get Mixed Stream</button>
<select id="mixer-options">
<option value="multiple-cameras-default">Multiple Cameras (Default)</option>
<option value="multiple-cameras-customized">Multiple Cameras (Customized)</option>
<option value="camera-screen">Camera + Screen</option>
<option value="microphone-mp3">Microphone + Mp3</option>
</select>
<br>
<div id="video-preview" style="margin-top: 15px;">
<h2 style="display: block;"></h2>
<video controls playsinline autoplay></video>
</div>
</section>
<script>
var videoPreview = document.querySelector('video');
var mixerOptions = document.querySelector('#mixer-options');
mixerOptions.onchange = function() {
localStorage.setItem('mixer-selected-options', this.value);
location.reload();
};
if(localStorage.getItem('mixer-selected-options')) {
mixerOptions.value = localStorage.getItem('mixer-selected-options');
}
function updateMediaHTML(html) {
videoPreview.parentNode.querySelector('h2').innerHTML = html;
}
document.querySelector('#btn-get-mixed-stream').onclick = function() {
this.disabled = true;
if(mixerOptions.value === 'camera-screen') {
updateMediaHTML('Capturing screen');
getMixedCameraAndScreen();
}
if(mixerOptions.value === 'multiple-cameras-default' || mixerOptions.value === 'multiple-cameras-customized') {
updateMediaHTML('Capturing camera');
getMixedMultipleCameras(mixerOptions.value === 'multiple-cameras-customized');
}
if(mixerOptions.value === 'microphone-mp3') {
updateMediaHTML('Capturing mp3+microphone');
getMixedMicrophoneAndMp3();
}
};
function afterScreenCaptured(screenStream) {
navigator.mediaDevices.getUserMedia({
video: true
}).then(function(cameraStream) {
screenStream.fullcanvas = true;
screenStream.width = screen.width; // or 3840
screenStream.height = screen.height; // or 2160
cameraStream.width = parseInt((30 / 100) * screenStream.width);
cameraStream.height = parseInt((30 / 100) * screenStream.height);
cameraStream.top = screenStream.height - cameraStream.height;
cameraStream.left = screenStream.width - cameraStream.width;
fullCanvasRenderHandler(screenStream, 'Your Screen!');
normalVideoRenderHandler(cameraStream, 'Your Camera!');
var mixer = new MultiStreamsMixer([screenStream, cameraStream]);
mixer.frameInterval = 1;
mixer.startDrawingFrames();
videoPreview.srcObject = mixer.getMixedStream();
updateMediaHTML('Mixed Screen+Camera!');
addStreamStopListener(screenStream, function() {
mixer.releaseStreams();
videoPreview.pause();
videoPreview.src = null;
cameraStream.getTracks().forEach(function(track) {
track.stop();
});
});
});
}
function getMixedCameraAndScreen() {
if(navigator.getDisplayMedia) {
navigator.getDisplayMedia({video: true}).then(screenStream => {
afterScreenCaptured(screenStream);
});
}
else if(navigator.mediaDevices.getDisplayMedia) {
navigator.mediaDevices.getDisplayMedia({video: true}).then(screenStream => {
afterScreenCaptured(screenStream);
});
}
else {
getScreenId(function (error, sourceId, screen_constraints) {
navigator.mediaDevices.getUserMedia(screen_constraints).then(function(screenStream) {
afterScreenCaptured(screenStream);
});
});
}
}
function getMixedMultipleCameras(isCustomized) {
navigator.mediaDevices.getUserMedia({video: true }).then(function(cameraStream) {
var mixer;
if(isCustomized === true) {
var fullCanvasStream = new MediaStream();
cameraStream.getTracks().forEach(function(track) {
fullCanvasStream.addTrack(track);
});
fullCanvasStream.fullcanvas = true;
fullCanvasStream.width = screen.width; // or 3840
fullCanvasStream.height = screen.height; // or 2160
fullCanvasRenderHandler(fullCanvasStream, 'Full Canvas Stream');
cameraStream.width = parseInt((30 / 100) * fullCanvasStream.width);
cameraStream.height = parseInt((30 / 100) * fullCanvasStream.height);
cameraStream.top = fullCanvasStream.height - cameraStream.height;
cameraStream.left = fullCanvasStream.width - cameraStream.width;
var clonedCamera2 = new MediaStream();
cameraStream.getTracks().forEach(function(track) {
clonedCamera2.addTrack(track);
});
clonedCamera2.width = parseInt((30 / 100) * fullCanvasStream.width);
clonedCamera2.height = parseInt((30 / 100) * fullCanvasStream.height);
clonedCamera2.top = fullCanvasStream.height - clonedCamera2.height;
clonedCamera2.left = fullCanvasStream.width - (clonedCamera2.width * 2);
normalVideoRenderHandler(clonedCamera2, 'Someone');
normalVideoRenderHandler(cameraStream, 'You!');
mixer = new MultiStreamsMixer([fullCanvasStream, clonedCamera2, cameraStream]);
}
else {
normalVideoRenderHandler(cameraStream, 'Camera', function(context, x, y, width, height, idx, textToDisplay) {
context.font = '30px Georgia';
textToDisplay += ' #' + (idx + 1);
var measuredTextWidth = parseInt(context.measureText(textToDisplay).width);
x = x + (parseInt((width - measuredTextWidth)) / 2);
y = height - 40;
if(idx == 2 || idx == 3) {
y = (height * 2) - 40;
}
if(idx == 4 || idx == 5) {
y = (height * 3) - 40;
}
context.strokeStyle = 'rgb(255, 0, 0)';
context.fillStyle = 'rgba(255, 255, 0, .5)';
roundRect(context, x - 20, y - 25, measuredTextWidth + 40, 35, 20, true);
var gradient = context.createLinearGradient(0, 0, width * 2, 0);
gradient.addColorStop('0', 'magenta');
gradient.addColorStop('0.5', 'blue');
gradient.addColorStop('1.0', 'red');
context.fillStyle = gradient;
context.fillText(textToDisplay, x, y);
});
mixer = new MultiStreamsMixer([cameraStream, cameraStream, cameraStream, cameraStream]);
}
mixer.frameInterval = 1;
mixer.startDrawingFrames();
videoPreview.srcObject = mixer.getMixedStream();
updateMediaHTML('Mixed Multiple Cameras!');
});
}
function getMixedMicrophoneAndMp3() {
updateMediaHTML('Select Mp3 file.');
getMp3Stream(function(mp3Stream) {
navigator.mediaDevices.getUserMedia({
audio: true
}).then(function(microphoneStream) {
var audioMixer = new MultiStreamsMixer([microphoneStream, mp3Stream]);
// audioMixer.useGainNode = false;
var audioPreview = document.createElement('audio');
audioPreview.controls = true;
audioPreview.autoplay = true;
audioPreview.srcObject = audioMixer.getMixedStream();
videoPreview.replaceWith(audioPreview);
videoPreview = audioPreview;
var secondsLeft = 6;
(function looper() {
secondsLeft--;
if(secondsLeft < 0) {
updateMediaHTML('Mixed Microphone+Mp3!');
return;
}
updateMediaHTML('Seconds left: ' + secondsLeft);
setTimeout(looper, 1000);
})();
var recorder = RecordRTC(audioMixer.getMixedStream(), {
recorderType: StereoAudioRecorder
});
recorder.startRecording();
setTimeout(function() {
recorder.stopRecording(function() {
audioPreview.removeAttribute('srcObject');
audioPreview.removeAttribute('src');
audioPreview.src = URL.createObjectURL(recorder.getBlob());
});
}, 5000)
});
});
}
function getMp3Stream(callback) {
var selector = new FileSelector();
selector.accept = '*.mp3';
selector.selectSingleFile(function(mp3File) {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
var gainNode = context.createGain();
gainNode.connect(context.destination);
gainNode.gain.value = 0; // don't play for self
var reader = new FileReader();
reader.onload = (function(e) {
// Import callback function
// provides PCM audio data decoded as an audio buffer
context.decodeAudioData(e.target.result, createSoundSource);
});
reader.readAsArrayBuffer(mp3File);
function createSoundSource(buffer) {
var soundSource = context.createBufferSource();
soundSource.buffer = buffer;
soundSource.start(0, 0 / 1000);
soundSource.connect(gainNode);
var destination = context.createMediaStreamDestination();
soundSource.connect(destination);
// durtion=second*1000 (milliseconds)
callback(destination.stream, buffer.duration * 1000);
}
}, function() {
document.querySelector('#btn-get-mixed-stream').disabled = false;
alert('Please select mp3 file.');
});
}
// via: https://www.webrtc-experiment.com/webrtcpedia/
function addStreamStopListener(stream, callback) {
stream.addEventListener('ended', function() {
callback();
callback = function() {};
}, false);
stream.addEventListener('inactive', function() {
callback();
callback = function() {};
}, false);
stream.getTracks().forEach(function(track) {
track.addEventListener('ended', function() {
callback();
callback = function() {};
}, false);
track.addEventListener('inactive', function() {
callback();
callback = function() {};
}, false);
});
}
function fullCanvasRenderHandler(stream, textToDisplay) {
// on-video-render:
// called as soon as this video stream is drawn (painted or recorded) on canvas2d surface
stream.onRender = function(context, x, y, width, height, idx) {
context.font = '50px Georgia';
var measuredTextWidth = parseInt(context.measureText(textToDisplay).width);
x = x + (parseInt((width - measuredTextWidth)) - 40);
y = y + 80;
context.strokeStyle = 'rgb(255, 0, 0)';
context.fillStyle = 'rgba(255, 255, 0, .5)';
roundRect(context, x - 20, y - 55, measuredTextWidth + 40, 75, 20, true);
var gradient = context.createLinearGradient(0, 0, width * 2, 0);
gradient.addColorStop('0', 'magenta');
gradient.addColorStop('0.5', 'blue');
gradient.addColorStop('1.0', 'red');
context.fillStyle = gradient;
context.fillText(textToDisplay, x, y);
};
}
function normalVideoRenderHandler(stream, textToDisplay, callback) {
// on-video-render:
// called as soon as this video stream is drawn (painted or recorded) on canvas2d surface
stream.onRender = function(context, x, y, width, height, idx, ignoreCB) {
if(!ignoreCB && callback) {
callback(context, x, y, width, height, idx, textToDisplay);
return;
}
context.font = '40px Georgia';
var measuredTextWidth = parseInt(context.measureText(textToDisplay).width);
x = x + (parseInt((width - measuredTextWidth)) / 2);
y = (context.canvas.height - height) + 50;
context.strokeStyle = 'rgb(255, 0, 0)';
context.fillStyle = 'rgba(255, 255, 0, .5)';
roundRect(context, x - 20, y - 35, measuredTextWidth + 40, 45, 20, true);
var gradient = context.createLinearGradient(0, 0, width * 2, 0);
gradient.addColorStop('0', 'magenta');
gradient.addColorStop('0.5', 'blue');
gradient.addColorStop('1.0', 'red');
context.fillStyle = gradient;
context.fillText(textToDisplay, x, y);
};
}
/**
* Draws a rounded rectangle using the current state of the canvas.
* If you omit the last three params, it will draw a rectangle
* outline with a 5 pixel border radius
* @param {CanvasRenderingContext2D} ctx
* @param {Number} x The top left x coordinate
* @param {Number} y The top left y coordinate
* @param {Number} width The width of the rectangle
* @param {Number} height The height of the rectangle
* @param {Number} [radius = 5] The corner radius; It can also be an object
* to specify different radii for corners
* @param {Number} [radius.tl = 0] Top left
* @param {Number} [radius.tr = 0] Top right
* @param {Number} [radius.br = 0] Bottom right
* @param {Number} [radius.bl = 0] Bottom left
* @param {Boolean} [fill = false] Whether to fill the rectangle.
* @param {Boolean} [stroke = true] Whether to stroke the rectangle.
*/
// via: http://stackoverflow.com/a/3368118/552182
function roundRect(ctx, x, y, width, height, radius, fill, stroke) {
if (typeof stroke == 'undefined') {
stroke = true;
}
if (typeof radius === 'undefined') {
radius = 5;
}
if (typeof radius === 'number') {
radius = {
tl: radius,
tr: radius,
br: radius,
bl: radius
};
} else {
var defaultRadius = {
tl: 0,
tr: 0,
br: 0,
bl: 0
};
for (var side in defaultRadius) {
radius[side] = radius[side] || defaultRadius[side];
}
}
ctx.beginPath();
ctx.moveTo(x + radius.tl, y);
ctx.lineTo(x + width - radius.tr, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr);
ctx.lineTo(x + width, y + height - radius.br);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height);
ctx.lineTo(x + radius.bl, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl);
ctx.lineTo(x, y + radius.tl);
ctx.quadraticCurveTo(x, y, x + radius.tl, y);
ctx.closePath();
if (fill) {
ctx.fill();
}
if (stroke) {
ctx.stroke();
}
}
</script>
<section class="experiment">
<h2>How to use MultiStreamsMixer?</h2>
<pre style="background:#fdf6e3;color:#586e75"><span style="color:#93a1a1">// https://cdn.webrtc-experiment.com/MultiStreamsMixer.js</span>
<span style="color:#268bd2">var</span> audioMixer <span style="color:#859900">=</span> <span style="color:#859900">new</span> MultiStreamsMixer<span style="color:#93a1a1">(</span><span style="color:#268bd2">[</span>microphone1, microphone2<span style="color:#268bd2">]</span><span style="color:#93a1a1">)</span>;
<span style="color:#93a1a1">// record using MediaRecorder API</span>
<span style="color:#268bd2">var</span> recorder <span style="color:#859900">=</span> <span style="color:#859900">new</span> MediaRecorder<span style="color:#93a1a1">(</span>audioMixer.getMixedStream<span style="color:#93a1a1">(</span><span style="color:#93a1a1">)</span><span style="color:#93a1a1">)</span>;
<span style="color:#93a1a1">// or share using WebRTC</span>
rtcPeerConnection.addStream<span style="color:#93a1a1">(</span>audioMixer.getMixedStream<span style="color:#93a1a1">(</span><span style="color:#93a1a1">)</span><span style="color:#93a1a1">)</span>;
</pre>
</section>
<!--
<section class="experiment">
<h2 class="header" id="updates" style="color: red; padding-bottom: .1em;"><a href="https://github.com/muaz-khan/MultiStreamsMixer/issues" target="_blank">Issues</a>
</h2>
<div id="github-issues"></div>
</section>
<section class="experiment">
<h2 class="header" id="updates" style="color: red; padding-bottom: .1em;"><a href="https://github.com/muaz-khan/MultiStreamsMixer/commits/master" target="_blank">Latest Updates</a>
</h2>
<div id="github-commits"></div>
</section>
-->
<section class="experiment"><small id="send-message"></small></section>
</article>
<a href="https://github.com/muaz-khan/MultiStreamsMixer" class="fork-left"></a>
<footer>
<p>
<a href="https://www.webrtc-experiment.com/">WebRTC Experiments</a> © <a href="https://plus.google.com/+MuazKhan" rel="author" target="_blank">Muaz Khan</a>
<a href="mailto:muazkh@gmail.com" target="_blank">muazkh@gmail.com</a>
</p>
</footer>
<!-- commits.js is useless for you! -->
<script>
window.useThisGithubPath = 'muaz-khan/MultiStreamsMixer';
</script>
<script src="https://cdn.webrtc-experiment.com/commits.js" async></script>
</body>
</html>
{
"name": "multistreamsmixer",
"preferGlobal": true,
"version": "1.0.7",
"author": {
"name": "Muaz Khan",
"email": "muazkh@gmail.com",
"url": "https://muazkhan.com/"
},
"description": "Pass multiple streams (e.g. screen+camera or multiple-cameras) and get single stream.",
"scripts": {
"start": "node server.js"
},
"main": "./MultiStreamsMixer.js",
"repository": {
"type": "git",
"url": "https://github.com/muaz-khan/MultiStreamsMixer.git"
},
"keywords": [
"webrtc",
"multistreamsmixer",
"webrtc-library",
"library",
"javascript",
"rtcweb",
"webrtc-experiment",
"javascript-library",
"muaz",
"muaz-khan"
],
"analyze": false,
"license": "MIT",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/muaz-khan/MultiStreamsMixer/issues",
"email": "muazkh@gmail.com"
},
"homepage": "https://www.webrtc-experiment.com/MultiStreamsMixer/",
"_id": "multistreamsmixer@",
"_from": "multistreamsmixer@",
"devDependencies": {
"grunt": "0.4.5",
"grunt-bump": "0.7.0",
"grunt-cli": "0.1.13",
"grunt-contrib-concat": "0.5.1",
"grunt-contrib-uglify": "0.11.0",
"grunt-jsbeautifier": "0.2.10",
"load-grunt-tasks": "3.4.0",
"grunt-contrib-watch": "^1.1.0"
}
}
// http://127.0.0.1:9001
// http://localhost:9001
var server = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs');
function serverHandler(request, response) {
var uri = url.parse(request.url).pathname,
filename = path.join(process.cwd(), uri);
fs.exists(filename, function(exists) {
if (!exists) {
response.writeHead(404, {
'Content-Type': 'text/plain'
});
response.write('404 Not Found: ' + filename + '\n');
response.end();
return;
}
if (filename.indexOf('favicon.ico') !== -1) {
return;
}
var isWin = !!process.platform.match(/^win/);
if (fs.statSync(filename).isDirectory() && !isWin) {
filename += '/index.html';
} else if (fs.statSync(filename).isDirectory() && !!isWin) {
filename += '\\index.html';
}
fs.readFile(filename, 'binary', function(err, file) {
if (err) {
response.writeHead(500, {
'Content-Type': 'text/plain'
});
response.write(err + '\n');
response.end();
return;
}
var contentType;
if (filename.indexOf('.html') !== -1) {
contentType = 'text/html';
}
if (filename.indexOf('.js') !== -1) {
contentType = 'application/javascript';
}
if (contentType) {
response.writeHead(200, {
'Content-Type': contentType
});
} else response.writeHead(200);
response.write(file, 'binary');
response.end();
});
});
}
var app;
app = server.createServer(serverHandler);
app = app.listen(process.env.PORT || 9001, process.env.IP || "0.0.0.0", function() {
var addr = app.address();
console.log("Server listening at", addr.address + ":" + addr.port);
});
<?php
namespace App\Commands;
use App\Commands\Command;
use Illuminate\Contracts\Bus\SelfHandling;
class VmjChat extends Command implements SelfHandling
{
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the command.
*
* @return void
*/
public function handle()
{
//
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Foundation\Inspiring;
class Inspire extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'inspire';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Display an inspiring quote';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->comment(PHP_EOL.Inspiring::quote().PHP_EOL);
}
}
<?php
namespace App\Console\Commands;
//use App\Commands\Command;
use Illuminate\Console\Command;
class VmjChat extends Command
{
protected $signature = 'vmj:chat {vid}';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the command.
*
* @return void
*/
public function handle(){
$vid = $this->argument('vid');
echo 'Proverka Vmj Chat.['.$vid.']....';
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use App\Http\Controllers\WebSocketController;
class WebSocketServer extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'websocket:init';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Initializing Websocket server to receive and manage connections';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
$server = IoServer::factory(
new HttpServer(
new WsServer(
new WebSocketController()
)
),
8085
);
$server->run();
}
}
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Commands\Inspire::class,
//Commands\VmjChat::class,
//Commands\WebSocketServer::class
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('inspire')
->hourly();
}
}
<?php
namespace App\Events;
abstract class Event
{
//
}
<?php
namespace App\Exceptions;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
HttpException::class,
ModelNotFoundException::class,
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Exception $e
* @return void
*/
public function report(Exception $e)
{
return parent::report($e);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Illuminate\Http\Response
*/
public function render($request, Exception $e)
{
if ($e instanceof ModelNotFoundException) {
$e = new NotFoundHttpException($e->getMessage(), $e);
}
if( method_exists($e, "getStatusCode")){
if ($e->getStatusCode() == 404) {
return \Response::view('errors.404',array(),404);
}
}
if( substr($e->getMessage(),0,9) == "fsockopen" ){
header('Content-Type: application/json');
return \Response::view('errors.200',array(),200);
} else {
return parent::render($request, $e);
}
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AdminsController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
public function __construct(){
}
protected function Begin(Request $request){
if( !Auth::check() ){
return redirect('/');
}
//$settingPath = str_replace("settings/","", $request->path());
//var_dump($settingPath);
//if( empty($input) ){ return false; }
//if( empty($input["func"]) ){ return false; } else { $method = $input["func"]; }
//var_dump("sdfsfsdf");
return view('admins'); //,['path',$settingPath]
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use Mail;
use App\User;
use App\Vms;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AjaxController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
static protected $vms;
public function __construct()
{
//if(self::noAuth()){return "";}
self::$vms = new Vms;
//$this->middleware('guest', ['except' => 'getLogout']);
//return view('ajax',['data'=>$input]);
}
protected function noAuth(){
if( !Auth::check() ){
//header('Location: /logout/');
header('Content-Type: application/json');
echo json_encode( array("error"=>"No authentication") );
return true;
}
}
protected function doAction(Request $request){
$input = $request->all();
$webinars = false;
if( empty($input) ){ return false; }
if( empty($input["func"]) ){ return false; } else { $method = $input["func"]; }
$webinar_funcs = array(
"addNewWebinar",
"editMyWebinar",
"removeMyWebinar",
"enterToWebinarById",
"exitFromWebinar",
"enterToMyLastWebinar",
"uploadFiles",
"chatupload",
"pictureupload",
"getRoomFiles",
"removeFileFromRoom",
"sendMailInvite",
"getRoomVisitors",
"getwebinarfiles"
);
if( in_array($input["func"], $webinar_funcs ) ) {
$uid = \Session::get('uid');
$typeuser = \Session::get('typeuser');
if(( !is_numeric($uid)) || ( $typeuser != "webinar")){
/*header('Content-Type: application/json');
echo json_encode( array("error"=>"No Webinar speaker (Uid:".$uid."), (Utype:".$typeuser.")" ) );
return true;//$webinars = false; //
*/
$webinars = false;
} else {
$webinars = true;
}
}
$exclude_funcs = array(
"checkWrtcLogin",
"checkWrtcPassAndEnter",
"checkEnterLogin",
"checkPassAndEnter",
"saveConfMessage",
"getConfNumberInfos",
"checkWrtcMdpUidEnter",
"getAllChatMessages",
"checkLoginAndRegister",
"checkLoginForRegister",
"checkWebinarLogin",
"checkWebinarPassAndEnter",
"isConfStreaming"
);
/*HERE I COMMENTED VARIABLE "$webinars" BECAUSE IT WAS UNDEFINED*/
if( (!in_array($input["func"], $exclude_funcs )) && (!$webinars) ){
if(self::noAuth()){return "";}
}
$is_method = method_exists($this, $method);
if( $is_method ){
$ajaxReturn = $this->$method($input);
if( is_array($ajaxReturn) ){
header('Content-Type: application/json');
if(!empty($ajaxReturn["room"])){
$fmdf_room = array();
$fmdf_room["offline_members"] = (!empty($ajaxReturn["room"]["offline_members"])) ? $ajaxReturn["room"]["offline_members"] : "";
$fmdf_room["members"] = (!empty($ajaxReturn["room"]["members"])) ? $ajaxReturn["room"]["members"] : "";
$fmdf_room["video-layout"] = (!empty($ajaxReturn["room"]["video-layout"])) ? $ajaxReturn["room"]["video-layout"] : "1x1";
$fmdf_room["member_count"] = (!empty($ajaxReturn["room"]["member_count"])) ? $ajaxReturn["room"]["member_count"] : 0;
//unset( $fmdf_room["run_time"] );
//unset( $fmdf_room["channels"] );
$jsonRoomReturn = json_encode( $fmdf_room );
$ajaxReturn["mdf"] = md5($jsonRoomReturn);
}
echo json_encode( $ajaxReturn );
}
}
}
protected function get_videos_list($input){
$videos_path = config('vms.videos_path');
$files = array_diff(scandir($videos_path), array('.', '..'));
//if( empty($files) ) {return "";}
$elems = array();
foreach( $files as $vf ){
if( substr($vf,-4) == ".mp4" ){
$elems[] = $vf;
}
}
return array("result"=>"ok",'videos'=>$elems, 'path'=>$videos_path);
}
protected function checkLoginForRegister($input){
$uid = self::$vms->checkLoginForRegister($input);
if( $uid ){
return array("result"=>"ok");
} else {
return array("result"=>"error",'msg'=>trans('username_already_used'));
}
}
protected function checkWebinarLogin($input){
$uid = self::$vms->checkLoginForRegister($input);
if( $uid ){
return array("result"=>"ok", "uid"=>$uid);
} else {
return array("result"=>"error",'msg'=>trans('username_not_found'));
}
}
protected function exitFromWebinar($input){
if( self::$vms->exitFromWebinar($input) ){
return array("result"=>"ok");
} else {
return array("result"=>"error");
}
}
protected function enterToMyLastWebinar($input){
if( self::$vms->enterToMyLastWebinar($input) ){
return array("result"=>"ok");
} else {
return array("result"=>"error");
}
}
protected function remove_record_file($input){
if(empty($input["file"])){ return array("result"=>"error","msg"=>"File not found"); }
if(file_exists("/recordings/".$input["file"])){
unlink("/recordings/".$input["file"]);
return array("result"=>"ok","msg"=>"Record deleted!");
} else {
return array("result"=>"error","msg"=>"File not found");
}
}
protected function uploadFiles($data){
if( self::$vms->uploadFiles($data) ){
return array("result"=>"ok");
} else {
return array("result"=>"error");
}
}
protected function enterToWebinarById($input){
if( self::$vms->enterToWebinarById($input) ){
return array("result"=>"ok");
} else {
return array("result"=>"error");
}
}
protected function isConfStreaming($input){
$res = self::$vms->isConfStreaming($input["room"]);
if( $res === true ){
return array("result"=>"ok");
} else {
return array("result"=>"error",'msg'=>$res);
}
}
protected function checkWebinarPassAndEnter($input){
$res = self::$vms->checkWebinarPassAndEnter($input);
if( $res === true ){
return array("result"=>"ok");
} else {
return array("result"=>"error",'msg'=>$res);
}
}
protected function checkLoginAndRegister($input){
$uid = self::$vms->checkLoginAndRegister($input);
if( is_numeric($uid) ){
return array("result"=>"ok",'user'=>$uid);
} else {
return array("result"=>"error",'msg'=>$uid);
}
}
protected function checkWrtcPassAndEnter($input){
$wl = self::$vms->checkWrtcPassAndEnter($input);
if( is_array($wl) ){
return array("result"=>"ok",'user'=>$wl);
} else {
return array("result"=>"error",'msg'=>'Password wrong',"err"=>$wl);
}
}
protected function checkWrtcMdpUidEnter($input){
if( $wl = self::$vms->checkWrtcMdpUidEnter($input) ){
return array("result"=>"ok",'user'=>$wl);
} else {
return array("result"=>"error",'msg'=>'Mdp wrong');
}
}
protected function checkWrtcLogin($input){
if( $wl = self::$vms->checkWrtcLogin($input) ){
return array("result"=>"ok",'user'=>$wl);
} else {
return array("result"=>"error",'msg'=>'User not found');
}
}
protected function checkEnterLogin($input){
$uid = DB::table('users')->where('login', $input['login'])->value('id');
if( !empty($uid) ){
return array("result"=>"ok","uid"=>$uid);
} else {
return array("result"=>"error",'msg'=>'Unknown user');
}
}
protected function saveConfMessage($input){ //from, to, msg, fromnumber, tonumber, room
if( empty($input["msg"]) ){
return array("result"=>"error",'msg'=>"Msg is empty");
}
if( strlen( str_replace(" ","",$input["msg"]) ) < 1 ){
return array("result"=>"error",'msg'=>"Msg is empty");
}
if( empty($input["room"]) ){
return array("result"=>"error",'msg'=>"Room is empty");
}
$from = (!empty($input["from"]) ) ? $input["from"] : "";
$to = (!empty($input["to"])) ? $input["to"] : "";
$fromnumber = (!empty($input["fromnumber"])) ? $input["fromnumber"] : "";
$tonumber = (!empty($input["tonumber"])) ? $input["tonumber"] : "";
$confInfo = self::$vms-> getConferenceArray($input["room"]);
$confuuid = (!empty($confInfo["conference_uuid"])) ? $confInfo["conference_uuid"] : "";
/*
$data = array(
'"'.$from.'"',
'"'.time().'"',
'"'.$to.'"',
'"'.$input["msg"].'"',
'"'.$fromnumber.'"',
'"'.$tonumber.'"',
'"'.$input["room"].'"',
'"'.$confuuid.'"',
);
*/
$mid = DB::table('messages')->insertGetId([
"from" => $from,
"date" => time(),
"to" => $to,
"msg" => $input["msg"],
"fromnumber" => $fromnumber,
"tonumber" => $tonumber,
"room" => $input["room"],
"uuid" => $confuuid,
]);
//if( $mid = DB::insertGetId('insert into messages (`from`, `date`, `to`, `msg`, `fromnumber`, `tonumber`, `room`, `uuid`) values ('.implode(",",$data).')') ){
if( $mid ){
//$vMsg = str_replace(" ","_",$input["msg"]);
//$vMsg = "ло привет друзья!!!\n"; //$input["msg"];
$vMsg = preg_replace('/\r\n|\r|\n/u', '', $input["msg"]);
//$remResult = self::$vms->apiCommand("conference ".$input["room"]." vid-banner All clear");
//$remResult = self::$vms->apiCommand("conference ".$input["room"].' vid-banner All \''.$vMsg.'\'');
$msgFile = "/tmp/".$input["room"]."_msg.png";
//if( !file_exists($msfFile) )
//unlink($msgFile);
$imgAns = self::$vms->create_png_from_text(["text"=>$from.": ".$vMsg,"file"=>$msgFile]);
//var_dump($imgAns);
if( $imgAns == "ok" ){
//$remResult = self::$vms->apiCommand("conference ".$input["room"]." vid-fgimg clear");
$remResult = self::$vms->apiCommand("conference ".$input["room"].' vid-fgimg '.$msgFile.'');
//$remResult = self::$vms->apiCommand("conference ".$input["room"].' vid-bgimg '.$msgFile.'');
}
/*sleep(1);
$tcnt = mb_strlen($vMsg);
$wcnt=1;
while ($tcnt >= $wcnt) {
$sMsg = mb_substr($vMsg,$wcnt);
$imgAns = self::$vms->create_png_from_text(["text"=>$from.": ".$sMsg,"file"=>$msgFile]);
if( $imgAns == "ok" ){
$remResult = self::$vms->apiCommand("conference ".$input["room"].' vid-fgimg '.$msgFile.'');
}
sleep(2000);
$wcnt++;
}
*/
return array("result"=>"ok",'mid'=>$mid,"imgans"=>$imgAns );
} else {
return array("result"=>"error",'msg'=>'Error saving to DB');
}
}
protected function getConfNumberInfos($input){
if( $infos = self::$vms->getConfNumberInfos($input) ){
return array("result"=>"ok",'infos'=>$infos);
} else {
return array("result"=>"error",'msg'=>'Info not found');
}
}
protected function add_webinar_listener_block($input){
if( empty($input["room"]) ){ return array("result"=>"error",'msg'=>trans("Room number is empty")); }
if( empty($input["lid"]) ){ return array("result"=>"error",'msg'=>trans("Listener id is empty")); }
DB::table('visits')->where('id', $input["lid"])->update(array("active"=>"B"));
}
protected function checkPassAndEnter($input){
$dbPass = DB::table('users')->where('id', $input['uid'])->value('password');
if (\Hash::check($input['password'], $dbPass)) {
//session()->regenerate();
Session::put('uid', $input['uid']);
//session(['uid' => $input['uid']]);
Auth::loginUsingId($input['uid'], true);
//var_dump(\Auth::check());
return array("result"=>"ok",'uid'=>$input['uid']);
} elseif($input['password']==$dbPass){
Session::put('uid', $input['uid']);
Auth::loginUsingId($input['uid'], true);
return array("result"=>"ok",'uid'=>$input['uid']);
}else {
return array("result"=>"error",'msg'=>'Wrong password-['.$input['password'].']-['.$dbPass.']');
}
}
protected function checkRegister($input){
//$db = DB::table('users')-> where($input['name']);
}
protected function removeFileFromRoom($input){
if( empty($input["room"]) ){ return array("result"=>"error",'msg'=>"Room number is empty"); }
if( empty($input["fid"]) ){ return array("result"=>"error",'msg'=>"File ID is empty"); }
if( is_numeric($input["fid"]) ){
$arFiles = DB::table('files')->where('id', $input["fid"])->get();
if( empty($arFiles) ){
return array("result"=>"error",'msg'=>"File not found!");
}
$arFile = json_decode(json_encode($arFiles[0]),true);
$fpath = $arFile["path"].$arFile["uploadedname"];
if( unlink($fpath) ){
DB::table('files')->where('id',$input["fid"])->delete();
return array("result"=>"ok",'msg'=>"File removed");
}
}
}
protected function getRoomFiles($input){
if( empty($input["room"]) ){ return array("result"=>"error",'msg'=>"Room number is empty"); }
$arFiles = DB::table('files')->select('date', 'desc', 'id', 'room', 'filename', 'size', 'type')->where('room', $input["room"])->get();
return array("result"=>"ok",'files'=>$arFiles );
}
protected function getwebinarfiles($input){
$arFiles = DB::table('files')->where('room',$input["room"])->orderBy('id', 'desc')->get();
return array( "result"=> "ok", "files" => $arFiles);
}
protected function chatupload($input){
if( empty( $_FILES['file'] ) ){ return array("result"=>"error",'msg'=>"No file for upload"); }
/*
Таблица: files
id int(25)
filename varchar(250)
uploadedname varchar(200)
date int(20)
room varchar(10)
path varchar(200)
desc text
*/
//$bdir = '/var/www/html/test.vmajlis.uz';
$bdir = dirname(dirname(dirname(__DIR__)));
$udir = '/storage/uploads/';
$orig_filename = $_FILES['file']['name'];
$fsize = $_FILES['file']['size'];
$upl_filename = self::$vms->generateRandomString(20);
$ftype = pathinfo($orig_filename, PATHINFO_EXTENSION);
if( move_uploaded_file( $_FILES['file']['tmp_name'], $bdir.$udir.$upl_filename ) ){
if( $fid = DB::table('files')->insertGetId(
[
'filename' => $orig_filename,
'uploadedname' => $upl_filename,
'date' => time(),
'uid' => (!empty($input["room"])) ? $input["room"] : "",
'path' => $bdir.$udir,
'desc' => (!empty($input["desc"])) ? $input["desc"] : "",
"size" => $fsize,
"type" => $ftype
]
) ){
return array("result"=>"ok",'fid'=>$fid, "filename"=>$orig_filename, "filesize"=>$fsize, "filetype"=>$ftype );
//return array("result"=>"ok",'file'=>$udir.$_FILES['file']['name'], "filename"=>$_FILES['file']['name'] );
} else {
return array("result"=>"error",'msg'=>"File not saved to db");
}
} else {
return array("result"=>"error",'msg'=>"File not uploaded");
}
}
protected function pictureupload($input){
if( empty( $_FILES['picture'] ) ){ return array("result"=>"error",'msg'=>"No file for upload"); }
if( empty($input['uid']) ){ return array("result"=>"error",'msg'=>"No uid"); }
if ( ($_FILES['picture']['type'] !== 'image/jpeg') && ($_FILES['picture']['type'] !== 'image/png') && ($_FILES['picture']['type'] !== 'image/jpg') )
{
return array("result"=>"error",'msg'=>"No file for upload,file's type is not defined".json_encode($_FILES['picture']));
}
$bdir = dirname(dirname(dirname(__DIR__)));
$udir = '/storage/uploads/avatars/';
$orig_filename = $_FILES['picture']['name'];
$fsize = $_FILES['picture']['size'];
$upl_filename = self::$vms->generateRandomString(20);
$ftype = pathinfo($orig_filename, PATHINFO_EXTENSION);
if( move_uploaded_file( $_FILES['picture']['tmp_name'], $bdir.$udir.$upl_filename ) ){
$desc = (!empty($input["desc"])) ? $input["desc"] : "";
$fid = DB::table('files')->where('uid',(int)$input["uid"])->where('desc',$desc)->value('id');
if(!empty($fid)){
DB::table('files')
->where('uid',(int)$input["uid"])
->where('desc',$desc)
->update([
'filename' => $orig_filename,
'uploadedname' => $upl_filename,
'date' => time(),
'path' => $bdir.$udir,
"size" => $fsize,
"type" => $ftype
]);
} else {
$fid = DB::table('files')->insertGetId(
[
'filename' => $orig_filename,
'uploadedname' => $upl_filename,
'date' => time(),
'uid' => (int)$input["uid"] ,
'path' => $bdir.$udir,
'desc' => (!empty($input["desc"])) ? $input["desc"] : "",
"size" => $fsize,
"type" => $ftype
]
);
}
if($fid ){
return array("result"=>"ok",'fid'=>$fid, "filename"=>$orig_filename, "filesize"=>$fsize, "filetype"=>$ftype );
//return array("result"=>"ok",'file'=>$udir.$_FILES['file']['name'], "filename"=>$_FILES['file']['name'] );
} else {
return array("result"=>"error",'msg'=>"File not saved to db");
}
} else {
return array("result"=>"error",'msg'=>"File not uploaded");
}
}
protected function getUserPass($input){
if( $upass = self::$vms->getUserPass($input) ){
return array("result"=>"ok",'upass'=>$upass);
} else {
return array("result"=>"error",'msg'=>'Users not found');
}
}
protected function getOneUserInfo($input){
if( $users = self::$vms->getOneUserInfo($input["num"]) ){
return array("result"=>"ok",'user'=>$users);
} else {
return array("result"=>"error",'msg'=>'User not found');
}
}
protected function getAllUsers(){
//$vms = new \Vms;
if( $users = self::$vms->getAllUsers() ){
return array("result"=>"ok",'users'=>$users, "rooms"=>self::$vms->getAllRooms());
} else {
return array("result"=>"error",'msg'=>'Users not found');
}
}
protected function getAllRooms($input){
$vms = self::$vms;
return $vms->getAllRooms();
}
protected function getActiveRoomData($input){
if( empty( $input["room"] ) ){ return array("result"=>"error"); }
return array("result"=>"ok", "time"=>time(), "room"=>self::$vms->getActiveRoomData($input['room']) );
}
protected function saveUserData($input){
$upass = self::$vms->getUserPass($input);
$nopass = false;
if(empty($input['password']) && ($input["savetype"]=="edit")){
$nopass = true;
}
$userPass = (!empty($input['password'])) ? $input['password'] : $upass;
if(empty($userPass)){
return array("result"=>"error",'msg'=>'Password is empty['.$userPass.']');
}
if( (empty($input['num'])) && (empty($input['number'])) ){
return array("result"=>"error",'msg'=>'Number is empty');
}
if( empty($input['name']) ){
return array("result"=>"error",'msg'=>'Name is empty');
}
/*if( ( (empty($input['num'])) && (empty($input['number']))) || ( $userPass ) || (empty($input['name'])) ){
return array("result"=>"error",'msg'=>'Some field is empty');
}*/
$arData = array(
"num" => (!empty($input['num'])) ? $input['num'] : $input['number'],
"password" => $userPass,
"nopass" => $nopass,
"name" => $input['name'],
"room" => (!empty($input['room'])) ? $input['room'] : "7777",
"ptzurl" => (!empty($input['ptzurl'])) ? $input['ptzurl'] : "",
"bandwidth_in" => (!empty($input['bandwidth_in'])) ? $input['bandwidth_in'] : "",
"bandwidth_out" => (!empty($input['bandwidth_out'])) ? $input['bandwidth_out'] : ""
);
if( !empty($input["login"]) ) { $arData["login"] = $input["login"]; }
if( !empty($input["type"]) ) { $arData["typeuser"] = $input["type"]; }
return array("result"=>"ok", "msg"=>self::$vms->saveUser($arData));
}
protected function getChannelsInfo($input){
return self::$vms->getChannelsInfo();
}
protected function isFreeNumber($input){
//$vms = new Vms;
if( empty($input['number']) ) {return array("result"=>"error");}
if( !self::$vms->is_number_isset($input['number'])){
return array("result"=>"ok");
} else {
return array("result"=>"error");
}
}
protected function getAllRoomsStatus($input){
//$vms = new Vms;
return self::$vms->getAllActiveRooms();
}
protected function getAllWssUsers($input){
//$vms = new Vms;
return self::$vms->getAllWssUsers();
}
protected function changeProfileLayout($input){
return self::$vms->changeProfileLayout($input);
}
protected function get_one_layout($input){
if( empty($input["layout"]) ){ return array("result"=>"error", "msg"=>"Layout is empty"); }
$remResult = self::$vms->get_one_layout($input["layout"]);
if( is_array($remResult) ){
return array("result"=>"ok", "layout"=>$remResult);
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function conf_record_stop($input){
$remResult = self::$vms->conf_record_stop($input);
if( $remResult == "ok" ){
return array("result"=>"ok");
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function conf_record_start($input){
$remResult = self::$vms->conf_record_start($input);
if( $remResult == "ok" ){
return array("result"=>"ok");
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function remove_room_file($input){
$remResult = self::$vms->remove_room_file($input['number']);
if( $remResult == "ok" ){
return array("result"=>"ok");
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function getRoomVisitors($i){
if( empty($i['room']) ) {return array("result"=>"error", "msg"=>"Room is empty");}
$arVisitors = DB::table('visits')->where('room', $i["room"])->where('active', "Y")->orderBy('id', 'desc')->get();
if( !empty($arVisitors) ){
return array("result"=>"ok", "visitors"=>$arVisitors);
} else {
return array("result"=>"error", "msg"=>trans("no_visitors_in_room"));
}
}
protected function enterVisitorToRoom($i){
if( empty($i['room']) ) {return array("result"=>"error", "msg"=>"Room is empty");}
if( empty($i['name']) ) {return array("result"=>"error", "msg"=>"Name is empty");}
////getUserOS getUserIP getUserBrowser
$vid = DB::table('visits')->insertGetId([
"datetime" => time(),
"ip" => self::$vms->getUserIP(),
"room" => $i['room'],
"desc" => "",
"active" => "Y",
"name" => $i['name'],
"browser" => self::$vms->getUserBrowser(),
"os" => self::$vms->getUserOS(),
]);
if( !empty($vid) ){
return array("result"=>"ok");
} else {
return array("result"=>"error", "msg"=>trans("cannot_enter_to_room"));
}
}
protected function sendMailInvite($i){
if( empty($i["tomail"]) ){ return array("result"=>"error", "msg"=>trans("lang.empty_speaker_mail") ); }
if( empty($i["speakername"]) ){ return array("result"=>"error", "msg"=>trans("lang.empty_speaker_name") ); }
if( empty($i["subject"]) ){ return array("result"=>"error", "msg"=>trans("lang.empty_wbr_subject") ); }
if( empty($i["link"]) ){ return array("result"=>"error", "msg"=>trans("lang.empty_wbr_link") ); }
$i["msubj"]= trans("lang.wbr_subject_temp").$i["subject"];
//$data = array("speakername"=>$i["speakername"],"subject"=>$i["subject"],"link"=>"https://webinar.vmajlis.uz/WLqH5Y6WcM");
Mail::send('emails.invitewebinar', $i, function ($message) use ($i){
//$message->from('no-reply@vmajlis.uz', 'vMajlisTest1');
//$message->to('knavruzov@technounit.uz')->cc('bar@example.com');
$message->to($i["tomail"])->subject( $i["msubj"]);
//$message->subject($subject);
//echo "Massage sent";
});
return array("result"=>"ok");
}
protected function removeUser($input){
if( empty($input['number']) ) {return array("result"=>"error", "msg"=>"Number is empty");}
$remResult = self::$vms->removeUser($input['number']);
if( $remResult == "ok" ){
return array("result"=>"ok");
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function getMainMenu($input){
return array("result"=>"ok",
"menu"=> array(
array("title"=>"Комнаты", "icon"=>"fa fa-id-card", "path"=>"/"),
array("title"=>"Пользователи", "icon"=>"fa fa-users", "path"=>"/users"),
array("title"=>"Администраторы", "icon"=>"fa fa-user-secret", "path"=>"/admins"),
array("title"=>"Разбиения", "icon"=>"fa fa-table", "path"=>"/layouts"),
array("title"=>"Настройки", "icon"=>"fa fa-cogs", "path"=>"/settings"),
//array("title"=>"Управление пользователями","class"=>"edit_users", "icon"=>"fa fa-edit", "path"=>"#"),
array("title"=>"Выход", "icon"=>"fa fa-sign-out-alt", "path"=>"/logout"),
)
);
}
protected function getRoomRecs($input){
$remResult = self::$vms->list_recordings($input);
if( is_array($remResult) ) {
return array("result"=>"ok", "recs"=>$remResult);
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function getMyList($input){
return array("result"=>"ok","list"=>"test","list4"=>"test2","list3"=>"test3","list2"=>"test4");
}
protected function get_all_layouts($input){
$remResult = self::$vms->get_all_layouts($input);
if( !empty($remResult) ){
if( is_array($remResult) ) {
return array("result"=>"ok", "layouts"=>$remResult);
} else {
return array("result"=>"error", "msg"=>$remResult);
}
} else {
return array("result"=>"error", "msg"=>"Layouts not found");
}
}
protected function get_all_profiles($input){
//return self::$vms->getAllProfiles();
$remResult = self::$vms->getAllProfiles();
if( !empty($remResult) ){
if( is_array($remResult) ) {
return array("result"=>"ok", "profiles"=>$remResult);
} else {
return array("result"=>"error", "msg"=>$remResult);
}
} else {
return array("result"=>"error", "msg"=>"Profiles not found");
}
}
protected function saveRoom($input){
$remResult = self::$vms->saveRoom($input);
if( $remResult == "ok" ){
return array("result"=>"ok");
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function getSysInfo($input){
$info_array = self::$vms->sysFullInfo($input);
return $info_array;
}
protected function doCommand($input){
if( empty($input["command"]) ){ return array("result"=>"error", "msg"=>"No Command"); }
$input["command"] = str_replace("+"," ",$input["command"]);
$remResult = self::$vms->apiCommand($input["command"]);
if( empty($remResult) ){ return array("result"=>"error"); }
return array("result"=>"ok", "responce"=>$remResult);
}
protected function allCalls($input){
return self::$vms->allCalls();
}
protected function getAllChatMessages($input){
if( !empty($input["room"]) ){
//$confInfo = self::$vms-> getConferenceArray($input["room"]);
//if (!empty($confInfo["conference_uuid"])) {
/*function sortdown($a, $b){
return strcmp($b["reyting"],$a["reyting"]);
}*/
$arMsgs = DB::table('messages')->where('room', $input["room"])->orderBy('id', 'desc')->limit(10)->get();
//$arMsgs = DB::table('messages')->where('uuid', $confInfo["conference_uuid"])->get();
//$arMsgs = collect($arMsgss)->toArray();
usort($arMsgs, function($a, $b){
return strcmp($a->id,$b->id);
});
if( empty($arMsgs) ){
return array("result"=>"error", "msg"=>"No messages");
}
$ret = array("result"=>"ok", "messages"=>$arMsgs);
$minDb = DB::table('messages')->where('room', $input["room"])->min('id');
$minRec = $arMsgs[0]->id;
$ret["more"] = array($minDb,$minRec) ;
return $ret;
//}
//else {
// return array("result"=>"error", "msg"=>"No messages");
//}
} else {
return array("result"=>"error", "msg"=>"Room is empty");
}
}
protected function checkPort($input){
if( empty($input["host"]) || empty($input["port"]) ) { return array("result"=>"error"); }
$remResult = self::$vms->is_port_open( $input["host"], $input["port"] );
return array("result"=>"ok", "answer"=>$remResult);
}
protected function getActiveItemData($input){
$remResult = self::$vms->getActiveItemData($input);
if( is_array($remResult)){
return array("result"=>"ok","answer"=>$remResult);
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
protected function editMyWebinar($input){
$arw = self::$vms->editMyWebinar($input);
if( is_array($arw) ){
return array("result"=>"ok","arw"=>$arw);
} else {
return array("result"=>"error", "msg"=>"Неопределенная ошибка!");
}
}
protected function removeMyWebinar($input){
$remAns = self::$vms->removeMyWebinar($input);
if( !empty($remAns) ){
return array("result"=>"error", "msg"=>$remAns);
} else {
return array("result"=>"ok");
}
}
protected function addNewWebinar($input){
$wid = self::$vms->addNewWebinar($input);
if( is_numeric($wid) ){
return array("result"=>"ok","wid"=>$wid);
} else {
return array("result"=>"error", "msg"=>$wid);
}
}
protected function saveProfile($input){
if( empty($input['name']) ) {return array("result"=>"error", "msg"=>"Name is required");}
$remResult = self::$vms->saveProfile($input);
if( $remResult == "ok" ){
return array("result"=>"ok");
} else {
return array("result"=>"error", "msg"=>$remResult);
}
}
}
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Http\RedirectResponse;
class AuthController extends Controller
{
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'getLogout']);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'phone' => 'required|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'phone' => $data['phone'],
'password' => bcrypt($data['password']),
]);
}
public function postLogin(Request $request)
{
$auth = false;
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->has('remember'))) {
$auth = true; // Success
}
if ($request->ajax()) {
return response()->json([
'auth' => $auth,
'intended' => URL::previous()
]);
} else {
return redirect()->intended(URL::route('dashboard'));
}
return redirect(URL::route('login_page'));
}
protected function postRegister(){
return "Registering in....";
}
protected function getLogin(){
return view('auth.login');
}
protected function getRegister(){
return view('auth.register');
}
protected function getLogout(){
\Session::forget('ulogin');
\Session::forget('uname');
\Session::forget('unumber');
\Session::forget('upass');
\Session::forget('utocall');
\Auth::logout();
//return redirect()->action( 'UserController@profile', ['sw_msg' => "Thank you!"]);
session(['sw_msg' => "Thank you!"]);
return redirect('/'); //->route('/', ['sw_msg' => "Thank you!"]);
}
}
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
class PasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Create a new password controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ChatsController extends Controller
{
protected function Begin(){
/*if( Auth::check() ){
$user = \Auth::user();
$uid = \Session::get('uid');
//var_dump($user);
return view('dashboard',["user"=>$user,"uid"=>$uid]);
} elseif( !empty(\Session::get('ulogin')) ) {
return redirect('/meet');
} else {
if( $jmsg = session('sw_msg') ){
\Session::forget('sw_msg');
return view('welcome',["sw_msg"=>$jmsg]);
}*/
return view('welcome');
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class ClicktocallController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
public function __construct(){
}
protected function Begin(Request $request){
if( !Auth::check() ){
return redirect('/');
}
$settingPath = str_replace("settings/","", $request->path());
//var_dump($settingPath);
//if( empty($input) ){ return false; }
//if( empty($input["func"]) ){ return false; } else { $method = $input["func"]; }
return view('clicktocall');
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
abstract class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class FilesController extends Controller
{
protected function Begin(Request $request){
$fid = substr(str_replace("webinar/","", $request->path()),6);
if( is_numeric($fid) ){
$arFiles = DB::table('files')->where('id', $fid)->get();
if( empty($arFiles) ){
return "File not found![".$fid."]";
die();
}
$arFile = json_decode(json_encode($arFiles[0]),true);
$fpath = $arFile["path"].$arFile["uploadedname"];
$this->file_force_download($fpath,$arFile["filename"]);
/*
["id"]=> int(8)
["filename"]=> string(62) "Инструкция_по_приёму_и_переводу.doc"
["uploadedname"]=> string(20) "D4QL49_gw2qOA6mgtlmq"
["date"]=> int(1550667807)
["room"]=> string(4) "8906"
["path"]=> string(48) "/var/www/html/online.vmajlis.uz/storage/uploads/"
["desc"]=> string(0) ""
*/
//$fpath = htmlspecialchars(urldecode($fpath));
//$upldir = dirname(dirname(dirname(__DIR__))).'/storage/uploads' ;
/*
return view('files',[
"arrFile"=>$arFile,
]);
die();
*/
} else {
}
}
function file_force_download($file,$uname=false) {
if(empty($uname)) { $uname = basename($file); }
if (file_exists($file)) {
// сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт
// если этого не сделать файл будет читаться в память полностью!
if (ob_get_level()) {
ob_end_clean();
}
// заставляем браузер показать окно сохранения файла
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename=' . $uname);
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
// читаем файл и отправляем его пользователю
readfile($file);
exit;
}
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LangController extends Controller
{
protected function chooseLang(Request $request){
/*
if (App::isLocale('en')) {
//
}*/
$locl = str_replace("/","", $request->path());
//$locale = \Session::get('locale');
if( empty($locl) ){
\App::setLocale("ru");
\Session::set('locale', "ru");
} else {
\Session::set('locale', $locl);
\App::setLocale($locl);
}
/*
Route::get('/en', function () { \Session::set('locale', "en"); return back(); });
Route::get('/uz', function () { \Session::set('locale', "uz"); return back(); });
Route::get('/ru', function () { \Session::set('locale', "ru"); return back(); });
*/
//return redirect('/meet');
return back();
//var_dump( $locl );
//return view('welcome' [ "locale"=> $locale, 'locl'=>$locl ] );
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LayoutsController extends Controller
{
// use AuthenticatesAndRegistersUsers, ThrottlesLogins;
protected function Begin(){
if( !Auth::check() ){
return redirect('/');
}
$curLayout = \Session::get('current_layout');
//$lyt = str_replace("layouts/","", $request->path());
//$vData = ["all"=>$allLayouts];
$vData = [];
if( !empty($curLayout) ){ $vData["current"] = $curLayout; }
return view('layouts',$vData);
}
}
<?php
namespace App\Http\Controllers;
use Mail;
use App\User;
use App\Vms;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LiveController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
static protected $vms;
public function __construct()
{
self::$vms = new Vms;
/*if( Auth::check() ){
header('Content-Type: application/json');
echo json_encode( array("error"=>"no authorisation") );
}*/
//$this->middleware('guest', ['except' => 'getLogout']);
//return view('ajax',['data'=>$input]);
}
protected function getIP(Request $request){
//$allh = $request->headers()->all();
//var_dump($allh);
//var_dump("<HR>");
//var_dump($_SERVER);
}
protected function createUser($arPeer){
//$response = self::$vms->eRequest( "api reloadxml" );
}
protected function doAction(Request $request){
$uid = \Session::get('uid');
$typeuser = \Session::get('utype');
$uroom = \Session::get('uroom');
if( empty($typeuser) ){
return redirect('/');
}
if( $typeuser !== 'live' ){
return redirect('/');
}
$isLiveStream = self::$vms->isConfStreaming($uroom);
if( $isLiveStream ){
return view('livestream',["uroom"=>$uroom]);
} else {
return view('livestream_off',["uroom"=>$uroom]);
}
//return "The end";
//return view('livestream');
//$input = $request->all();
/*if( !empty($input["rname"]) ){
return self::createRoom($input["rname"]);
}*/
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Vms;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Cookie;
class MainController extends Controller
{
protected function Begin(Request $request){
$locale = \App::getLocale();
$vms = new Vms;
if( (!empty($_COOKIE["vmj_uid"])) && (!empty($_COOKIE["vmj_mdp"])) ){
$u_auth = $vms->checkWrtcPassAndEnter( array("uid"=>$_COOKIE["vmj_uid"],"mdpassword"=>$_COOKIE["vmj_mdp"]) );
if( !is_array($u_auth) ){
$clearCookie = true;
} else {
\Session::set('tologin',$u_auth["password"]);
}
}
if( Auth::check() ){
$user = \Auth::user();
$uid = \Session::get('uid');
//var_dump($user);
$arClients = $vms->getAllUsers();
return view('dashboard',[
"user"=>$user,
"uid"=>$uid,
"clients" => $arClients,
//"f_lang_text" => $f_lang_text,
//"s_lang_link" => $s_lang_link,
//"s_lang_text" => $s_lang_text,
]);
} elseif( !empty(\Session::get('ulogin')) ) {
$utype = \Session::get('utype');
$utype = (!empty($utype)) ? $utype : "";
if( $utype == "live" ){
return redirect('/live');
}
return redirect('/meet');
} else {
$welldatas = array(
//"f_lang_link" => $f_lang_link,
//"f_lang_text" => $f_lang_text,
//"s_lang_link" => $s_lang_link,
//"s_lang_text" => $s_lang_text,
"vmj_uid" => "",
"vmj_mdp" => "",
);
if( $jmsg = session('sw_msg') ){
\Session::forget('sw_msg');
$welldatas["sw_msg"] = $jmsg ;
}
return view('welcome',$welldatas);
}
}
}
//var_dump($vmj_mdp, $vmj_uid);
/*$langPath = base_path('resources/lang/'.$locale); //''; //resource_path('lang/'.\App::getLocale());
$allLang = collect(File::allFiles($langPath))->flatMap(function ($file) {
return [
($translation = $file->getBasename('.php')) => trans($translation),
];
})->toJson();
*/
//var_dump($allLang);
//var_dump( trans("lang.wbr_subject_temp") );
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\User;
use App\Vms;
use App\Mobile_Detect;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class MeetController extends Controller
{
protected function Begin(Request $request){
$detect = new Mobile_Detect;
$ulogin = \Session::get('ulogin');
$wurl = $request->url();
$devType = ($detect->isMobile()) ? "Mobile" : "PC";
if( $wurl == "http://webinar.vmajlis.uz/meet" ){
return view('meet',[
"uname"=>"Kulya",
"unumber"=>"7979",
"upass"=>"733d7be2196ff70efaf6913fc8bdcabf",
"utocall"=>"7777",
"ulogin"=>"kulya",
"dev"=>$devType
]);
} elseif( empty($ulogin) ){
return redirect('/');
} else {
$uname = \Session::get('uname');
$unumber = \Session::get('unumber');
$upass = \Session::get('upass');
$utocall = \Session::get('utocall');
$tologin = \Session::get('tologin');
$sharenum = \Session::get('sharenum');
//$user = \Auth::user();
$arRooms = DB::table('rooms')->get();
$uRooms = [];
foreach( $arRooms as $rm){
$rUsrs = json_decode($rm->users);
if(!empty($rUsrs)){
if( in_array($unumber,$rUsrs) ){
$uRooms[] = array("id"=>$rm->number, "value"=>$rm->name);
}
}
}
return view('meet',[
"uname"=>$uname,
"unumber"=>$unumber,
"upass"=>$upass,
"utocall"=>$utocall,
"ulogin"=>$ulogin,
"tologin"=>$tologin,
"urooms"=>$uRooms,
"sharenum"=>$sharenum,
"dev"=>$devType
]);
}
}
protected function Begintest(Request $request){
$detect = new Mobile_Detect;
$ulogin = \Session::get('ulogin');
$wurl = $request->url();
$devType = ($detect->isMobile()) ? "Mobile" : "PC";
if( empty($ulogin) ){
$vms = new Vms;
$testUser = DB::table('clients')->where('id', 34)->get();
$vms->enterToSystemIfGoodLogin($testUser[0]);
}
$uname = \Session::get('uname');
$unumber = \Session::get('unumber');
$upass = \Session::get('upass');
$utocall = \Session::get('utocall');
$tologin = \Session::get('tologin');
//$user = \Auth::user();
$arRooms = DB::table('rooms')->get();
$uRooms = [];
foreach( $arRooms as $rm){
if(!empty($rm->users)){
$rUsrs = json_decode($rm->users);
if(!empty($rUsrs)){
if( in_array($unumber,$rUsrs) ){
$uRooms[] = array("id"=>$rm->number, "value"=>$rm->name);
}
}
}
}
return view('meet',[
"uname"=>$uname,
"unumber"=>$unumber,
"upass"=>$upass,
"utocall"=>$utocall,
"ulogin"=>$ulogin,
"tologin"=>$tologin,
"urooms"=>$uRooms,
"dev"=>$devType
]);
}
protected function Share(Request $request){
$detect = new Mobile_Detect;
$devType = ($detect->isMobile()) ? "Mobile" : "PC";
$ulogin = \Session::get('ulogin');
$wurl = $request->url();
if($detect->isMobile()) {
return redirect('/meet');
}
if( empty($ulogin) ){
return redirect('/');
} else {
$sharename = \Session::get('sharename');
$sharenum = \Session::get('sharenum');
$shareroom = \Session::get('shareroom');
$sharepass = \Session::get('sharepass');
return view('sharing',[
"sharename"=>$sharename,
"sharenum"=>$sharenum,
"shareroom"=>$shareroom,
"sharepass"=>$sharepass,
"dev"=>$devType
]);
}
}
protected function Cam(Request $request){
return view('mycam');
}
protected function getSourceId(Request $request){
return view('getSourceId');
}
protected function rcControl(Request $request){
return view('remotecontrol');
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Mobile_Detect;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class MeetsController extends Controller
{
protected function Begin(Request $request){
$detect = new Mobile_Detect;
$ulogin = \Session::get('ulogin');
$wurl = $request->url();
$devType = ($detect->isMobile()) ? "Mobile" : "PC";
//var_dump($wurl);
if( $wurl == "https://online.vmajlis.uz/meets" ){
return view('meets',[
"uname"=>"Kulya",
"unumber"=>"7979",
"upass"=>"733d7be2196ff70efaf6913fc8bdcabf",
"utocall"=>"3333",
"ulogin"=>"kulya",
"dev"=>$devType
]);
}
/*elseif( empty($ulogin) ){
return redirect('/');
} else {
//$user = \Auth::user();
$uname = \Session::get('uname');
$unumber = \Session::get('unumber');
$upass = \Session::get('upass');
$utocall = \Session::get('utocall');
return view('meet',[
"uname"=>$uname,
"unumber"=>$unumber,
"upass"=>$upass,
"utocall"=>$utocall,
"ulogin"=>$ulogin,
"dev"=>$devType
]);
}*/
}
protected function Cam(Request $request){
return view('mycam');
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class PersonalCabinetController extends Controller
{
protected function Begin(Request $request){
$uid = \Session::get('uid');
$avatar_id = DB::table('files')->where('uid',$uid)->where('desc','avatar')->value('id');
$logo_id = DB::table('files')->where('uid',$uid)->where('desc','logo')->value('id');
//$room = str_replace("cabinet/","", $request->path());
return view('cabinet',['uid'=>$uid,'avatar_id'=>$avatar_id,'logo_id'=>$logo_id]);
/*if( !empty($ulogin) ){
return redirect('/');
} else {
//$user = \Auth::user();
$uname = \Session::get('uname');
$unumber = \Session::get('unumber');
$upass = \Session::get('upass');
$utocall = \Session::get('utocall');
return view('webinar');
}*/
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RecordingsController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
public function __construct(){
}
protected function Begin(Request $request){
$recs_path = $rPath = config('vms.records_path');
$recFile = str_replace("recordings/","", $request->path());
$fullFile = $recs_path.$recFile;
$fileSize = filesize($fullFile);
$humanSize = self::human_filesize($fileSize);
return response()->download($fullFile);
//return array("file"=>$recFile,"full"=>$recs_path.$recFile,"bytes"=>$fileSize, "hs"=>$humanSize);
//return view('settings',['path',$settingPath]);
//$file = basename($_GET['file']);
//$file = '/path/to/your/dir/'.$file;
/*
if(!file_exists($fuulFile)){ // file does not exist
return 'file not found';
} else {
header("Cache-Control: public");
header("Content-Description: File Transfer");
header("Content-Disposition: attachment; filename=$recFile");
header("Content-Type: application/zip");
header("Content-Transfer-Encoding: binary");
header("Content-length: $fileSize");
// read the file from disk
readfile($fuulFile);
}*/
}
function human_filesize($bytes, $decimals = 2) {
$sz = 'BKMGTP';
$factor = floor((strlen($bytes) - 1) / 3);
return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class RoomController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
public function __construct()
{
//$this->middleware('guest', ['except' => 'getLogout']);
//return view('ajax',['data'=>$input]);
}
protected function openRoom(Request $request){
if( !Auth::check() ){
return redirect('/');
}
$roomNumber = str_replace("room/","", $request->path());
return view('room',["number"=>$roomNumber]);
}
}
<?php
namespace App\Http\Controllers\Settings;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class SettingsController extends Controller
{
/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
// $this->middleware('settings', ['except' => 'getLogout']);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|max:255',
'phone' => 'required|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]);
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'phone' => $data['phone'],
'password' => bcrypt($data['password']),
]);
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class SettingsController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
public function __construct(){
}
protected function Begin(Request $request){
if( !Auth::check() ){
return redirect('/');
}
$settingPath = str_replace("settings/","", $request->path());
//var_dump($settingPath);
//if( empty($input) ){ return false; }
//if( empty($input["func"]) ){ return false; } else { $method = $input["func"]; }
return view('settings',['path',$settingPath]);
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use Mail;
use App\User;
use App\Vms;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class TestController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
static protected $vms;
public function __construct()
{
self::$vms = new Vms;
/*if( Auth::check() ){
header('Content-Type: application/json');
echo json_encode( array("error"=>"no authorisation") );
}*/
//$this->middleware('guest', ['except' => 'getLogout']);
//return view('ajax',['data'=>$input]);
}
protected function getIP(Request $request){
//$allh = $request->headers()->all();
//var_dump($allh);
//var_dump("<HR>");
var_dump($_SERVER);
}
protected function createUser($arPeer){
/*
num
password
name
room
*/
if( empty($arPeer["num"]) || empty($arPeer["password"]) || empty($arPeer["name"])){
return false;
}
if( empty($arPeer["room"]) ) { $pRoom = '7777';}
$peer_temp = '<include>
<user id="'.$arPeer["num"].'">
<params>
<param name="password" value="'.$arPeer["password"].'"/>
<param name="vm-password" value="'.$arPeer["password"].'"/>
</params>
<variables>
<variable name="toll_allow" value="domestic,international,local"/>
<variable name="accountcode" value="'.$arPeer["num"].'"/>
<variable name="user_context" value="default"/>
<variable name="effective_caller_id_name" value="'.$arPeer["name"].'"/>
<variable name="effective_caller_id_number" value="'.$arPeer["num"].'"/>
<variable name="outbound_caller_id_name" value="'.$arPeer["name"].'"/>
<variable name="outbound_caller_id_number" value="'.$arPeer["num"].'"/>
<variable name="callgroup" value="'.$pRoom.'"/>
</variables>
</user>
</include>';
if( self::save_user_file($arPeer["num"], $peer_temp) ){
//$vms = new Vms;
$response = self::$vms->eRequest( "api reloadxml" );
var_dump($response);
}
}
protected function myget(){
//$rooms_path = config('vms.rooms_path');
//var_dump($rooms_path);
/*
$response = self::$vms->eRequest( "api conference json_list" );
var_dump($response);
$arActiveRooms = json_decode($response."}]",true);
echo "<pre>";
var_dump($arActiveRooms);
echo "</pre>";
echo "<hr>";
*/
$vms = new Vms;
$rooms = $vms->getAllRooms();
echo "<pre>";
var_dump($rooms);
echo "</pre>";
echo "<hr>";
/*$users = self::$vms->getAllUsers();
echo "<pre>";
var_dump($users);
echo "</pre>";
echo "<hr>";*/
//$usersResponse = self::$vms->eRequest( "api list_users" );
//$arActiveUsers = json_decode($usersResponse."}]",true);
/*$roomXml = Vms::createRoomXml(array("number"=>7777,"name"=>"MyMajlis1","member_flags"=>"join-vid-floor"));
echo "<textarea row='50'>";
echo $roomXml;
echo "</textarea>";*/
}
protected function createRoom($name){
$room_temp = '<include>
<extension name="cdquality_stereo_conferences">
<condition field="destination_number" expression="(7777)">
<action application="answer"/>
<action application="send_display" data="vMajlis|$1"/>
<action application="set" data="conference_member_flags=join-vid-floor"/>
<action application="conference" data="$1@video-mcu-stereo"/>
</condition>
</extension>
</include>
';
if( self::save_room_file($name, $room_temp) ){
$vms = new Vms;
$response = $vms->eRequest( "api reloadxml" );
var_dump($response);
}
}
protected function save_user_file($name, $data){
$users_path = '/usr/local/freeswitch/conf/directory/vmajlis/';
if( $myfile = fopen($users_path."vmj_".$name.".xml", "w")) {
fwrite($myfile, $data);
fclose($myfile);
return true;
} else {
return false;
}
}
protected function save_room_file($name, $data){
$rooms_path = '/usr/local/freeswitch/conf/dialplan/vmajlis/';
//$rooms_path = '/var/www/html/test.vmajlis.uz/storage/vmj/';
if( $myfile = fopen($rooms_path."vmj_".$name.".xml", "w")) {
fwrite($myfile, $data);
fclose($myfile);
return true;
} else {
return false;
}
}
protected function doAction(Request $request){
/*$data = array("speakername"=>"Michael Jackson","subject"=>"Music is everythink of we!","link"=>"https://webinar.vmajlis.uz/WLqH5Y6WcM");
Mail::send('emails.invitewebinar', $data, function ($message) use ($data){
//$message->from('no-reply@vmajlis.uz', 'vMajlisTest1');
//$message->to('knavruzov@technounit.uz')->cc('bar@example.com');
$message->to('knavruzov@technounit.uz')->subject('S-'.$data["subject"]);
//$message->subject($subject);
echo "Massage sent";
});*/
return view('tests');
/*$input = $request->all();
if( !empty($input["rname"]) ){
return self::createRoom($input["rname"]);
}
if( !empty($input["pname"]) ){
return self::createUser(array(
"num" => $input["pnum"],
"name" => $input["pname"],
"password" => $input["ppass"],
));
}
if( !empty($input["f"]) ){
$method = $input["f"];
if( method_exists($this, $method) ){
$this->$method($input);
}
}
*/
}
}
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class TopngController extends Controller
{
public function __construct()
{
}
protected function Begin(Request $request){
$ptext = str_replace("topng/","", $request->path());
//var_dump($ptext);
$this->create_png_from_text(["text"=>urldecode($ptext),"width"=>1920,"height"=>1080]);
//return view('room',["number"=>$roomNumber]);
exit;
}
protected function create_png_from_text($args){
$font = "/usr/local/freeswitch/fonts/montserrat/Montserrat-Italic.otf";
if( empty($args) ){ $args = "Default";}
if( !is_array($args) ){
$args = array( 'text' => $args );
}
$width = ( !empty($args["width"]) ) ? (int)$args["width"] : 640; //1920; //640;
$height = ( !empty($args["height"]) ) ? (int)$args["height"] : 480; //1080; //480;
$text = $args["text"];
$file = ( !empty($args["file"]) ) ? $args["file"] : false;
if( $width > 1000 ){
$fontsize = 25;
} else {
$fontsize = 20;
}
$imgTxtBlock = imagecreate($width, 50);
$imgTxtBack = imagecreate($width, 50);
$img = imagecreate($width, $height);
imagecolorallocate($imgTxtBlock, 0, 0, 0);
imagecolorallocate($imgTxtBack, 255, 255, 255);
$black = imagecolorallocate($img, 3, 169, 244);
//imagecolortransparent($imgTxtBlock, $blue);
imagecolortransparent($img, $black);
$txtInTransparent = imagecolorallocate($imgTxtBlock, 255, 255, 255);
//$txtInTransparent = imagecolorallocate($img, 255, 255, 255);
$image_width = imagesx($img);
$image_height = imagesy($img);
$text_box = imagettfbbox($fontsize, 0, $font, $text);
$text_width = $text_box[0] - $text_box[2];
$text_height = $text_box[1] - $text_box[7];
$x = 100; //$image_width - ($text_width / 2);
$y = $image_height - ($text_height + 45);
imagettftext($imgTxtBlock, $fontsize, 0, 20, 30, $txtInTransparent, $font, $text);
//imagettftext($imgTxtBlock, $fontsize, 0, $x, $y, $txtInTransparent, $font, $text);
//imagettftext($img, $fontsize, 0, $x, $y, $txtInTransparent, $font, $text);
//imagettftext($img, $fontsize, 0, $x, $y, $txtInTransparent, $font, $text.'-['.$image_height.']-['.$text_height.']-['.$y.']' ); //For tests
// Copy and merge
imagecopymerge( $imgTxtBack, $imgTxtBlock, 0, 0, 0, 0, $image_width, 40, 80);
imagecopymerge( $img, $imgTxtBack, 0, $y, 0, 0, $image_width, 40, 100);
if( !empty($file) ){
imagepng($img, $file);
} else {
header('Content-Type: image/png');
imagepng($img);
}
imagedestroy($img);
imagedestroy($imgTxtBlock);
imagedestroy($imgTxtBack);
}
}
?>
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class UsersController extends Controller
{
protected function Begin(){
if( !Auth::check() ){
return redirect('/');
}
//$user = \Auth::user();
$unumber = \Session::get('unumber');
$upass = \Session::get('upass');
$utocall = \Session::get('utocall');
return view('users');
//} else {
//}
}
}
<?php
namespace App\Http\Controllers;
use App\Vms;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
class VmjchatController extends Controller
{
//static protected $vms;
protected function doAction(){ //Request $request
$arData = (!empty($GLOBALS["datas"]) ) ? $GLOBALS["datas"] : false;
if(!$arData){ return '{}';}
$msgDate = time();
if( !empty( $arData["messageId"] ) ){
$vid = (!empty($arData["vid"])) ? $arData["vid"] : "";
if(empty($vid)){
$vid = (!empty($arData["wid"])) ? $arData["wid"] : "";
}
$arMsg = array(
"date" => $msgDate,
"from" => (!empty($arData["name"])) ? $arData["name"] : "Unknown",
"fromid" => (!empty($arData["vid"])) ? $arData["vid"] : "",
"to" => (!empty($arData["to"])) ? $arData["to"] : "",
"room" => (!empty($arData["room"])) ? $arData["room"] : "",
"msg" => (!empty($arData["message"])) ? $arData["message"] : "NoText",
);
$newMsgId = DB::table('messages')->insertGetId($arMsg);
$toName = ($arData["room"] !== $arData["to"] ) ? DB::table('visits')->where("id", $arData["to"])->value("name") : '';
$arVisitorKeys = DB::table('visits')->select('id')->whereIn("id", $arData["userkeys"])->where('room', $arData["room"])->get();
$arKeysVtr = array();
foreach ($arVisitorKeys as $vkes ){
$arKeysVtr[] = $vkes->id;
}
return json_encode(array("newMsgId"=>$newMsgId,"newMsgDate"=>$msgDate,"toName"=>$toName,"vkeys"=>$arKeysVtr));
}
if( !empty( $arData["cmd"] ) ){
$vid = (!empty($arData["vid"])) ? $arData["vid"] : "";
if(empty($vid)){
$vid = (!empty($arData["wid"])) ? $arData["wid"] : "";
}
if($arData['cmd'] == "getLastMessages" ){
if (empty($arData['msgscnt'])){ $arData['msgscnt'] = 15; }
}
if($arData['cmd'] == "getAllVisitors" ){
if (empty($arData['msgscnt'])){ $arData['msgscnt'] = 15; }
if(!empty($arData["vid"])){
$arVstr = DB::table('visits')->where('id', $vid)->get();
} elseif(!empty($arData["wid"])){
$arVstr = array(array("wid"=>$vid));
} else {
$arVstr = array(array("error"=>"Unknown you"));
}
$newvisit = (!empty($arVstr)) ? $arVstr[0] : "";
$arLastMessages = DB::table('messages')
->join('visits', 'messages.to', '=', 'visits.id')
->select('messages.*', 'visits.name as toName')
->where('messages.room', $arData["room"])
->orderBy('id', 'desc')
->limit($arData['msgscnt'])
->get();
$arVisitors = DB::table('visits')->whereIn("id", $arData["userkeys"])->where('room', $arData["room"])->get();
//$arVisitors = DB::table('visits')->whereIn("active", "Y")->where('room', $arData["room"])->get();
$arLastMessages = array_reverse($arLastMessages);
return json_encode(array("count"=>count($arVisitors), "allvisitors"=> $arVisitors, "arLastMessages"=> $arLastMessages, "newvisit"=> $newvisit));
}
}
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class WebRTCController extends Controller
{
// use AuthenticatesAndRegistersUsers, ThrottlesLogins;
protected function Check(){
return "OK";
}
protected function Begin(){
if( !Auth::check() ){
return redirect('/');
}
$curLayout = \Session::get('current_layout');
//$lyt = str_replace("layouts/","", $request->path());
//$vData = ["all"=>$allLayouts];
$vData = [];
if( !empty($curLayout) ){ $vData["current"] = $curLayout; }
return view('layouts',$vData);
}
}
<?php
namespace App\Http\Controllers;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class WebSocketController extends Controller implements MessageComponentInterface{
private $connections = [];
/**
* When a new connection is opened it will be passed to this method
* @param ConnectionInterface $conn The socket/connection that just connected to your application
* @throws \Exception
*/
function onOpen(ConnectionInterface $conn){
echo "onOpen.....";
$this->connections[$conn->resourceId] = compact('conn') + ['user_id' => null];
}
/**
* This is called before or after a socket is closed (depends on how it's closed). SendMessage to $conn will not result in an error if it has already been closed.
* @param ConnectionInterface $conn The socket/connection that is closing/closed
* @throws \Exception
*/
function onClose(ConnectionInterface $conn){
echo "onClose.....";
$disconnectedId = $conn->resourceId;
unset($this->connections[$disconnectedId]);
foreach($this->connections as &$connection)
$connection['conn']->send(json_encode([
'offline_user' => $disconnectedId,
'from_user_id' => 'server control',
'from_resource_id' => null
]));
}
/**
* If there is an error with one of the sockets, or somewhere in the application where an Exception is thrown,
* the Exception is sent back down the stack, handled by the Server and bubbled back up the application through this method
* @param ConnectionInterface $conn
* @param \Exception $e
* @throws \Exception
*/
function onError(ConnectionInterface $conn, \Exception $e){
echo "onError.....";
$userId = $this->connections[$conn->resourceId]['user_id'];
echo "An error has occurred with user $userId: {$e->getMessage()}\n";
unset($this->connections[$conn->resourceId]);
$conn->close();
}
/**
* Triggered when a client sends data through the socket
* @param \Ratchet\ConnectionInterface $conn The socket/connection that sent the message to your application
* @param string $msg The message received
* @throws \Exception
*/
function onMessage(ConnectionInterface $conn, $msg){
echo "onMessage.....";
if(is_null($this->connections[$conn->resourceId]['user_id'])){
$this->connections[$conn->resourceId]['user_id'] = $msg;
$onlineUsers = [];
foreach($this->connections as $resourceId => &$connection){
$connection['conn']->send(json_encode([$conn->resourceId => $msg]));
if($conn->resourceId != $resourceId)
$onlineUsers[$resourceId] = $connection['user_id'];
}
$conn->send(json_encode(['online_users' => $onlineUsers]));
} else{
$fromUserId = $this->connections[$conn->resourceId]['user_id'];
$msg = json_decode($msg, true);
$this->connections[$msg['to']]['conn']->send(json_encode([
'msg' => $msg['content'],
'from_user_id' => $fromUserId,
'from_resource_id' => $conn->resourceId
]));
}
}
}
\ No newline at end of file
<?php
namespace App\Http\Controllers;
use App\User;
use App\Vms;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class WebinarController extends Controller
{
//static protected $vms;
protected function Begin(Request $request){
$wlink = str_replace("webinar/","", $request->path());
$input = $request->all();
$chuname = \Session::get('uname');
$vid = \Session::get('vid');
if( !empty($input["fbclid"]) ){
Session::put('fbclid',$input["fbclid"]);
return redirect('/'.$wlink);
}
$arWebinars = DB::table('webinars')->where('link', $wlink)->get();
if( !empty($arWebinars) ){
if( !empty($input["func"])){
if( $input["func"] == "authwebinarclient" ){
if( !empty($input["webinarname"]) ){
$uname = $input["webinarname"];
\Session::put('uname',$uname);
$arVisitor = [
'datetime' => time(),
'room' => $arWebinars[0]->room,
"ip" => Vms::getUserIP(),
"desc" => "",
"active" => "Y",
"name" => $uname,
"browser" => Vms::getUserBrowser(),
"os" => Vms::getUserOS(),
];
if( !empty($fbclid) ){
$arVisitor["desc"] = "Facebook::".$fbclid;
}
$vid = DB::table('visits')->insertGetId($arVisitor);
\Session::put('vid',$vid);
return redirect( '/' . $wlink );
}
}
}
if( empty($uname) ) {
if( !empty($chuname) ){
$uname = $chuname;
}
}
$arWebinar = $arWebinars[0];
$wdata = ['webinar'=>$arWebinars[0]];
if( !empty($uname) ){
$wdata['user'] = ['name'=>$uname];
$wdata['user']['vid'] = $vid;
return view('webinar',$wdata);
} else {
return view('webinarauth',$wdata);
}
} else {
return redirect('/');
}
/*if( !empty($ulogin) ){
return redirect('/');
} else {
//$user = \Auth::user();
$uname = \Session::get('uname');
$unumber = \Session::get('unumber');
$upass = \Session::get('upass');
$utocall = \Session::get('utocall');
return view('webinar');
}*/
}
}
<?php
namespace App\Http\Controllers;
use App\User;
use App\Vms;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class WebinarEnterController extends Controller
{
protected function Logout(){
\Session::flush();
return redirect('/');
}
protected function Begin(Request $request){
$uid = \Session::get('uid');
$locale = \App::getLocale();
if( $locale == "ru" ){
$f_lang_link = "/uz";
$f_lang_text = "O`zbekcha";
$s_lang_link = "/en";
$s_lang_text = "English";
}
if( $locale == "uz" ){
$f_lang_link = "/ru";
$f_lang_text = "Русский";
$s_lang_link = "/en";
$s_lang_text = "English";
}
if( $locale == "en" ){
$f_lang_link = "/uz";
$f_lang_text = "O`zbekcha";
$s_lang_link = "/ru";
$s_lang_text = "Русский";
}
if( !empty($uid) ){
$webinar = \Session::get('webinar');
$usertype = \Session::get('usertype');
$name = \Session::get('name');
$number = \Session::get('number');
$password = \Session::get('password');
$avatar = \Session::get('avatar');
$viewDatas = [
'uid'=>$uid ,
//"typeuser"=>$typeuser,
"name"=>$name,
"number"=>$number,
"password"=>$password,
"avatar"=>$avatar,
"f_lang_link" => $f_lang_link,
"f_lang_text" => $f_lang_text,
"s_lang_link" => $s_lang_link,
"s_lang_text" => $s_lang_text
];
$wurl = $request->url();
$viewDatas["webinarurl"] = $wurl;
// Get All Webinars of Current Speaker
$arWebinars = DB::table('webinars')->where('client', $uid)->get();
if( count($arWebinars) > 0 ) {
\Session::put('webinars', $arWebinars);
$viewDatas["webinars"]=$arWebinars;
}
// Set first webinar if not set other in session
/*var_dump('<hr>');
var_dump($webinar);
var_dump('<hr>');
*/
/*if( empty($webinar) ){
if( count($arWebinars) == 1 ) {
$webinar = json_decode(json_encode($arWebinars[0]),true);
$webinar['params'] = json_decode($webinar['params'],true);
\Session::put('webinar',$webinar);
//var_dump($webinar);
}
}*/
if( !empty($webinar) ){
$viewDatas["webinar"] = $webinar;
$viewDatas["webinarlink"] = $wurl.'/'.$webinar["link"];
}
//var_dump(trans("lang.wbr_subject_temp"));
return view('speaker',$viewDatas);
} else {
return view('enterweb',[
"f_lang_link" => $f_lang_link,
"f_lang_text" => $f_lang_text,
"s_lang_link" => $s_lang_link,
"s_lang_text" => $s_lang_text
]);
}
}
}
\ No newline at end of file
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
];
/**
* The application's route middleware.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'checkLang' => \App\Http\Middleware\checkLang::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
];
}
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class Authenticate
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new middleware instance.
*
* @param Guard $auth
* @return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('auth/login');
}
}
return $next($request);
}
}
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as BaseEncrypter;
class EncryptCookies extends BaseEncrypter
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
class RedirectIfAuthenticated
{
/**
* The Guard implementation.
*
* @var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* @param Guard $auth
* @return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->auth->check()) {
return redirect('/');
}
return $next($request);
}
}
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'/ajax',
];
}
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Facades\Session;
use Illuminate\Http\Request;
use Closure;
class checkLang
{
public function handle(Request $request, Closure $next)
{
$slocale = \Session::get('locale');
if( empty($slocale) ){
$cLocale = config('app.locale');
\App::setLocale($cLocale);
} else {
\App::setLocale($slocale);
}
return $next($request);
}
}
\ No newline at end of file
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest
{
//
}
<?php
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use App\Http\Middleware\checkLang;
if(!empty($GLOBALS["wbsock"])){
if ( $GLOBALS["wbsock"] == '123' ){
Route::get('/', 'VmjchatController@doAction');
Route::get('/{ws}', 'VmjchatController@doAction');
//die();
}
}
$appurl = config('app.url');
$arurl = explode("//",$appurl);
//var_dump( $_SERVER["HTTP_HOST"] );
$appdom = $_SERVER["HTTP_HOST"]; //$arurl[1]; //'online.vmajlis.uz'
Route::group(array('domain' => $appdom,'middleware'=>['checkLang']), function() {
// Маршруты языков...
Route::get('/en', 'LangController@chooseLang');
Route::get('/uz', 'LangController@chooseLang');
Route::get('/ru', 'LangController@chooseLang');
// Маршруты аутентификации...
Route::get('/login', 'Auth\AuthController@getLogin');
Route::post('/login', 'Auth\AuthController@postLogin');
Route::get('/logout', 'Auth\AuthController@getLogout');
// Маршруты регистрации...
Route::get('/register', 'Auth\AuthController@getRegister');
Route::post('/register', 'Auth\AuthController@postRegister');
Route::post('/ajax', 'AjaxController@doAction');
Route::get('/ajax', 'AjaxController@doAction');
//Route::get('/ajax', 'AjaxController@noAuth');
Route::get('/c2c', 'ClicktocallController@doAction');
//Route::get('/live', 'TestController@doAction');
Route::get('/live', 'LiveController@doAction');
Route::get('/yi', 'TestController@doAction');
Route::get('/test', 'TestController@doAction');
Route::get('/ip', 'TestController@getIP');
Route::get('/platform', 'WebRTCController@Check');
Route::get('/webinar', 'WebinarController@Begin');
Route::get('/webinar/{r}', 'WebinarController@Begin');
Route::get('/enterweb', 'WebinarEnterController@Begin');
Route::get('/enterweb/{w}', 'WebinarEnterController@Begin');
Route::get('/ok/{w}', 'WebRTCController@Check');
Route::get('/cam', 'MeetController@Cam');
Route::get('/chats', 'ChatsController@Begin');
Route::get('/meets', 'MeetsController@Begin');
Route::get('/share', 'MeetController@Share');
Route::get('/rc', 'MeetController@rcControl');
Route::get('/getSourceId', 'MeetController@getSourceId');
Route::get('/mytest', 'MeetController@Begintest');
Route::get('/meet', 'MeetController@Begin');
Route::get('/users', 'UsersController@Begin');
Route::get('/room','RoomController@openRoom');
Route::get('/room/{r}','RoomController@openRoom');
Route::get('/layouts/{p}','LayoutsController@Begin');
Route::get('/layouts','LayoutsController@Begin');
Route::get('/admins','AdminsController@Begin');
Route::get('/settings','SettingsController@Begin');
Route::get('/settings/{p}','SettingsController@Begin');
Route::get('/recordings/{r}','RecordingsController@Begin');
/*Route::get('recordings/{path}', function ($path) {
//return view('recordings',['path'=>$path]);
//return "/recordings/7777_23_Nov_13_42_57.mp4";
return response()->download("/recordings/7777_23_Nov_13_42_57.mp4");
});*/
Route::get('/icons', function () {
return view('icons');
});
Route::get('/topng', 'TopngController@Begin');
Route::get('/topng/{t}', 'TopngController@Begin');
Route::get('/', 'MainController@Begin');
});
Route::group(array('domain' => 'webinar.vmajlis.uz','middleware'=>['checkLang']), function() {
// Маршруты языков...
Route::get('/en', 'LangController@chooseLang');
Route::get('/uz', 'LangController@chooseLang');
Route::get('/ru', 'LangController@chooseLang');
// WebSockets
Route::get('/c', 'VmjchatController@doAction');
// Other routes
Route::post('/ajax', 'AjaxController@doAction');
Route::get('/ajax', 'AjaxController@doAction');
Route::get('/logout', 'WebinarEnterController@Logout');
Route::get('/cabinet', 'PersonalCabinetController@Begin');
Route::get('/meet', 'MeetController@Begin');
Route::get('/files', 'FilesController@Begin');
Route::get('/files/{f}', 'FilesController@Begin');
Route::get('/', 'WebinarEnterController@Begin');
//Route::get('/', 'WebinarController@Begin');
Route::get('/{r}', 'WebinarController@Begin');
Route::post('/{r}', 'WebinarController@Begin');
});
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
abstract class Job
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "onQueue" and "delay" queue helper methods.
|
*/
use Queueable;
}
<?php
namespace App;
/**
*
* @author Serban Ghita <serbanghita@gmail.com>
* @author Nick Ilyin <nick.ilyin@gmail.com>
* Original author: Victor Stanciu <vic.stanciu@gmail.com>
*
* @version 2.8.33
*/
class Mobile_Detect
{
/**
* Mobile detection type.
*
* @deprecated since version 2.6.9
*/
const DETECTION_TYPE_MOBILE = 'mobile';
/**
* Extended detection type.
*
* @deprecated since version 2.6.9
*/
const DETECTION_TYPE_EXTENDED = 'extended';
/**
* A frequently used regular expression to extract version #s.
*
* @deprecated since version 2.6.9
*/
const VER = '([\w._\+]+)';
/**
* Top-level device.
*/
const MOBILE_GRADE_A = 'A';
/**
* Mid-level device.
*/
const MOBILE_GRADE_B = 'B';
/**
* Low-level device.
*/
const MOBILE_GRADE_C = 'C';
/**
* Stores the version number of the current release.
*/
const VERSION = '2.8.33';
/**
* A type for the version() method indicating a string return value.
*/
const VERSION_TYPE_STRING = 'text';
/**
* A type for the version() method indicating a float return value.
*/
const VERSION_TYPE_FLOAT = 'float';
/**
* A cache for resolved matches
* @var array
*/
protected $cache = array();
/**
* The User-Agent HTTP header is stored in here.
* @var string
*/
protected $userAgent = null;
/**
* HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
* @var array
*/
protected $httpHeaders = array();
/**
* CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer.
* @var array
*/
protected $cloudfrontHeaders = array();
/**
* The matching Regex.
* This is good for debug.
* @var string
*/
protected $matchingRegex = null;
/**
* The matches extracted from the regex expression.
* This is good for debug.
*
* @var string
*/
protected $matchesArray = null;
/**
* The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
*
* @deprecated since version 2.6.9
*
* @var string
*/
protected $detectionType = self::DETECTION_TYPE_MOBILE;
/**
* HTTP headers that trigger the 'isMobile' detection
* to be true.
*
* @var array
*/
protected static $mobileHeaders = array(
'HTTP_ACCEPT' => array('matches' => array(
// Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
'application/x-obml2d',
// BlackBerry devices.
'application/vnd.rim.html',
'text/vnd.wap.wml',
'application/vnd.wap.xhtml+xml'
)),
'HTTP_X_WAP_PROFILE' => null,
'HTTP_X_WAP_CLIENTID' => null,
'HTTP_WAP_CONNECTION' => null,
'HTTP_PROFILE' => null,
// Reported by Opera on Nokia devices (eg. C3).
'HTTP_X_OPERAMINI_PHONE_UA' => null,
'HTTP_X_NOKIA_GATEWAY_ID' => null,
'HTTP_X_ORANGE_ID' => null,
'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
'HTTP_X_HUAWEI_USERID' => null,
// Reported by Windows Smartphones.
'HTTP_UA_OS' => null,
// Reported by Verizon, Vodafone proxy system.
'HTTP_X_MOBILE_GATEWAY' => null,
// Seen this on HTC Sensation. SensationXE_Beats_Z715e.
'HTTP_X_ATT_DEVICEID' => null,
// Seen this on a HTC.
'HTTP_UA_CPU' => array('matches' => array('ARM')),
);
/**
* List of mobile devices (phones).
*
* @var array
*/
protected static $phoneDevices = array(
'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m|Android [0-9.]+; Pixel',
'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6',
// @todo: Is 'Dell Streak' a tablet or a phone? ;)
'Dell' => 'Dell[;]? (Streak|Aero|Venue|Venue Pro|Flash|Smoke|Mini 3iX)|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b|XT1068|XT1092|XT1052',
'Samsung' => '\bSamsung\b|SM-G950F|SM-G955F|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C|SM-A310F|GT-I9190|SM-J500FN|SM-G903F|SM-J330F',
'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323|M257)',
'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533',
'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
'NokiaLumia' => 'Lumia [0-9]{3,4}',
// http://www.micromaxinfo.com/mobiles/smartphones
// Added because the codes might conflict with Acer Tablets.
'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b',
// @todo Complete the regex.
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
// http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
// Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
// http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
// http://fr.wikomobile.com
'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM',
'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
// Added simvalley mobile just for fun. They have some interesting devices.
// http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
// Wolfgang - a brand that is sold by Aldi supermarkets.
// http://www.wolfgangmobile.com/
'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
'Alcatel' => 'Alcatel',
'Nintendo' => 'Nintendo (3DS|Switch)',
// http://en.wikipedia.org/wiki/Amoi
'Amoi' => 'Amoi',
// http://en.wikipedia.org/wiki/INQ
'INQ' => 'INQ',
// @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser',
);
/**
* List of tablet devices.
*
* @var array
*/
protected static $tabletDevices = array(
// @todo: check for mobile friendly emails topic.
'iPad' => 'iPad|iPad.*Mobile',
// Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
// @see #442
// @todo Merge NexusTablet into GoogleTablet.
'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
// https://en.wikipedia.org/wiki/Pixel_C
'GoogleTablet' => 'Android.*Pixel C',
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
// http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)',
// Only the Surface tablets with Windows RT are considered mobile.
// http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
// http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
// Watch out for PadFone, see #132.
// http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\bP027\b|\bP024\b|\bP00C\b',
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
// http://www.acer.ro/ac/ro/RO/content/drivers
// http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
// http://us.acer.com/ac/en/US/content/group/tablets
// http://www.acer.de/ac/de/DE/content/models/tablets/
// Can conflict with Micromax and Motorola phones codes.
'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30',
// http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
// http://us.toshiba.com/tablets/tablet-finder
// http://www.toshiba.co.jp/regza/tablet/
'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
// http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
// http://www.lg.com/us/tablets
'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
// Prestigio Tablets http://www.prestigio.com/support
'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002',
// http://support.lenovo.com/en_GB/downloads/default.page?#
'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304F|TB-X304L|TB-8703F|Tab2A7-10F|TB2-X30L',
// http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
// http://www.yarvik.com/en/matrix/tablets/
'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
// http://www.intenso.de/kategorie_en.php?kategorie=33
// @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
// IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
'IRUTablet' => 'M702pro',
'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
// http://www.e-boda.ro/tablete-pc.html
'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
// http://www.allview.ro/produse/droseries/lista-tablete-pc/
'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
// http://wiki.archosfans.com/index.php?title=Main_Page
// @note Rewrite the regex format after we add more UAs.
'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
// http://www.ainol.com/plugin.php?identifier=ainol&module=product
'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
'NokiaLumiaTablet' => 'Lumia 2520',
// @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
// Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
// http://www.sony.jp/support/tablet/
'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712',
// http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8
'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
// db + http://www.cube-tablet.com/buy-products.html
'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
// http://www.cobyusa.com/?p=pcat&pcat_id=3001
'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
// http://www.match.net.cn/products.asp
'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10',
// http://www.msi.com/support
// @todo Research the Windows Tablets.
'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
// @todo http://www.kyoceramobile.com/support/drivers/
// 'KyoceraTablet' => null,
// @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
// 'IntextTablet' => null,
// http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
// http://www.imp3.net/14/show.php?itemid=20454
'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
// http://www.rock-chips.com/index.php?do=prod&pid=2
'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
// http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
'FlyTablet' => 'IQ310|Fly Vision',
// http://www.bqreaders.com/gb/tablets-prices-sale.html
'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))|Maxwell.*Lite|Maxwell.*Plus',
// http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
// http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09',
// Nec or Medias Tab
'NecTablet' => '\bN-06D|\bN-08D',
// Pantech Tablets: http://www.pantechusa.com/phones/
'PantechTablet' => 'Pantech.*P4100',
// Broncho Tablets: http://www.broncho.cn/ (hard to find)
'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
// http://versusuk.com/support.html
'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
// http://www.zync.in/index.php/our-products/tablet-phablets
'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
// http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
// https://www.nabitablet.com/
'NabiTablet' => 'Android.*\bNabi',
'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
// French Danew Tablets http://www.danew.com/produits-tablette.php
'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
// Texet Tablets and Readers http://www.texet.ru/tablet/
'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
// Avoid detecting 'PLAYSTATION 3' as mobile.
'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
// http://www.trekstor.de/surftabs.html
'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
// http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
// http://www.advandigital.com/index.php?link=content-product&jns=JP001
// because of the short codenames we have to include whitespaces to reduce the possible conflicts.
'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
// http://www.danytech.com/category/tablet-pc
'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
// http://www.galapad.net/product.html
'GalapadTablet' => 'Android.*\bG1\b(?!\))',
// http://www.micromaxinfo.com/tablet/funbook
'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
// http://www.karbonnmobiles.com/products_tablet.php
'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
// http://www.myallfine.com/Products.asp
'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
// http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
// http://www.yonesnav.com/products/products.php
'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
// http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
// China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
// http://www.gloryunion.cn/products.asp
// http://www.allwinnertech.com/en/apply/mobile.html
// http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
// @todo: Softwiner tablets?
// aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G
// http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
// http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
// @todo: add more tests.
'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027',
// http://hclmetablet.com/India/index.php
'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
// http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
// http://www.visture.com/index.asp
'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
// http://www.mijncresta.nl/tablet
'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
// MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
// Concorde tab
'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
// GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
// Modecom Tablets - http://www.modecom.eu/tablets/portal/
'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
// Vonino Tablets - http://www.vonino.eu/tablets
'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
// ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
// Storex Tablets - http://storex.fr/espace_client/support.html
// @note: no need to add all the tablet codes since they are guided by the first regex.
'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
// Generic Vodafone tablets.
'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497',
// French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
// Aka: http://www.essentielb.fr/
'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
// Ross & Moor - http://ross-moor.ru/
'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
// i-mobile http://product.i-mobilephone.com/Mobile_Device
'iMobileTablet' => 'i-mobile i-note',
// http://www.tolino.de/de/vergleichen/
'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
// AudioSonic - a Kmart brand
// http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72&currentPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1
'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
// AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
// @todo: add them gradually to avoid conflicts.
'AMPETablet' => 'Android.* A78 ',
// Skk Mobile - http://skkmobile.com.ph/product_tablets.php
'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
// Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
'TecnoTablet' => 'TECNO P9|TECNO DP8D',
// JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
// i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
// http://www.intracon.eu/tablet
'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
// http://www.xoro.de/produkte/
// @note: Might be the same brand with 'Simply tablets'
'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
// http://www1.viewsonic.com/products/computing/tablets/
'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
// https://www.verizonwireless.com/tablets/verizon/
'VerizonTablet' => 'QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1',
// http://www.odys.de/web/internet-tablet_en.html
'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
// http://www.captiva-power.de/products.html#tablets-en
'CaptivaTablet' => 'CAPTIVA PAD',
// IconBIT - http://www.iconbit.com/products/tablets/
'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
// http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi',
// Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+|V10 \b4G\b',
'JaytechTablet' => 'TPC-PA762',
'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
// http://www.digma.ru/support/download/
// @todo: Ebooks also (if requested)
'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
// http://www.evolioshop.com/ro/tablete-pc.html
// http://www.evolio.ro/support/downloads_static.html?cat=2
// @todo: Research some more
'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
// @todo http://www.lavamobiles.com/tablets-data-cards
'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
// http://www.breezetablet.com/
'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712',
// http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/
'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010',
// https://www.celkonmobiles.com/?_a=categoryphones&sid=2
'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
// http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b',
'MediacomTablet' => 'M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA',
// http://www.mi.com/en
'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
// http://www.nbru.cn/index.html
'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
// http://navroad.com/products/produkty/tablety/
// http://navroad.com/products/produkty/tablety/
'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
// http://leader-online.com/new_site/product-category/tablets/
// http://www.leader-online.net.au/List/Tablet
'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100',
// http://www.datawind.com/ubislate/
'UbislateTablet' => 'UbiSlate[\s]?7C',
// http://www.pocketbook-int.com/ru/support
'PocketBookTablet' => 'Pocketbook',
// http://www.kocaso.com/product_tablet.html
'KocasoTablet' => '\b(TB-1207)\b',
// http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm
'HisenseTablet' => '\b(F5281|E2371)\b',
// http://www.tesco.com/direct/hudl/
'Hudl' => 'Hudl HT7S3|Hudl 2',
// http://www.telstra.com.au/home-phone/thub-2/
'TelstraTablet' => 'T-Hub2',
'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bTP750\b|\bQTAQZ3\b|WVT101|TM1088|KT107'
);
/**
* List of mobile Operating Systems.
*
* @var array
*/
protected static $operatingSystems = array(
'AndroidOS' => 'Android',
'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
// @reference: http://en.wikipedia.org/wiki/Windows_Mobile
'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
// @reference: http://en.wikipedia.org/wiki/Windows_Phone
// http://wifeng.cn/?r=blog&a=view&id=106
// http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
// http://msdn.microsoft.com/library/ms537503.aspx
// https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
'iOS' => '\biPhone.*Mobile|\biPod|\biPad|AppleCoreMedia',
// http://en.wikipedia.org/wiki/MeeGo
// @todo: research MeeGo in UAs
'MeeGoOS' => 'MeeGo',
// http://en.wikipedia.org/wiki/Maemo
// @todo: research Maemo in UAs
'MaemoOS' => 'Maemo',
'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
'webOS' => 'webOS|hpwOS',
'badaOS' => '\bBada\b',
'BREWOS' => 'BREW',
);
/**
* List of mobile User Agents.
*
* IMPORTANT: This is a list of only mobile browsers.
* Mobile Detect 2.x supports only mobile browsers,
* it was never designed to detect all browsers.
* The change will come in 2017 in the 3.x release for PHP7.
*
* @var array
*/
protected static $browsers = array(
//'Vivaldi' => 'Vivaldi',
// @reference: https://developers.google.com/chrome/mobile/docs/user-agent
'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
'Dolfin' => '\bDolfin\b',
'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+$|Coast/[0-9.]+',
'Skyfire' => 'Skyfire',
'Edge' => 'Mobile Safari/[.0-9]* Edge',
'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS',
'Bolt' => 'bolt',
'TeaShark' => 'teashark',
'Blazer' => 'Blazer',
// @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari',
// http://en.wikipedia.org/wiki/Midori_(web_browser)
//'Midori' => 'midori',
//'Tizen' => 'Tizen',
'WeChat' => '\bMicroMessenger\b',
'UCBrowser' => 'UC.*Browser|UCWEB',
'baiduboxapp' => 'baiduboxapp',
'baidubrowser' => 'baidubrowser',
// https://github.com/serbanghita/Mobile-Detect/issues/7
'DiigoBrowser' => 'DiigoBrowser',
// http://www.puffinbrowser.com/index.php
'Puffin' => 'Puffin',
// http://mercury-browser.com/index.html
'Mercury' => '\bMercury\b',
// http://en.wikipedia.org/wiki/Obigo_Browser
'ObigoBrowser' => 'Obigo',
// http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NF-Browser',
// @reference: http://en.wikipedia.org/wiki/Minimo
// http://en.wikipedia.org/wiki/Vision_Mobile_Browser
'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
// @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser)
'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon',
);
/**
* Utilities.
*
* @var array
*/
protected static $utilities = array(
// Experimental. When a mobile device wants to switch to 'Desktop Mode'.
// http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
// https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
// https://developers.facebook.com/docs/sharing/best-practices
'Bot' => 'Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom',
'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
'DesktopMode' => 'WPDesktop',
'TV' => 'SonyDTV|HbbTV', // experimental
'WebKit' => '(webkit)[ /]([\w.]+)',
// @todo: Include JXD consoles.
'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|Nintendo Switch|PLAYSTATION|Xbox)\b',
'Watch' => 'SM-V700',
);
/**
* All possible HTTP headers that represent the
* User-Agent string.
*
* @var array
*/
protected static $uaHttpHeaders = array(
// The default User-Agent string.
'HTTP_USER_AGENT',
// Header can occur on devices using Opera Mini.
'HTTP_X_OPERAMINI_PHONE_UA',
// Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
'HTTP_X_DEVICE_USER_AGENT',
'HTTP_X_ORIGINAL_USER_AGENT',
'HTTP_X_SKYFIRE_PHONE',
'HTTP_X_BOLT_PHONE_UA',
'HTTP_DEVICE_STOCK_UA',
'HTTP_X_UCBROWSER_DEVICE_UA'
);
/**
* The individual segments that could exist in a User-Agent string. VER refers to the regular
* expression defined in the constant self::VER.
*
* @var array
*/
protected static $properties = array(
// Build
'Mobile' => 'Mobile/[VER]',
'Build' => 'Build/[VER]',
'Version' => 'Version/[VER]',
'VendorID' => 'VendorID/[VER]',
// Devices
'iPad' => 'iPad.*CPU[a-z ]+[VER]',
'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
'iPod' => 'iPod.*CPU[a-z ]+[VER]',
//'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
'Kindle' => 'Kindle/[VER]',
// Browser
'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'),
'Coast' => array('Coast/[VER]'),
'Dolfin' => 'Dolfin/[VER]',
// @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox
'Firefox' => array('Firefox/[VER]', 'FxiOS/[VER]'),
'Fennec' => 'Fennec/[VER]',
// http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
// https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
'Edge' => 'Edge/[VER]',
'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'),
// http://en.wikipedia.org/wiki/NetFront
'NetFront' => 'NetFront/[VER]',
'NokiaBrowser' => 'NokiaBrowser/[VER]',
'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
'Opera Mini' => 'Opera Mini/[VER]',
'Opera Mobi' => 'Version/[VER]',
'UCBrowser' => array( 'UCWEB[VER]', 'UC.*Browser/[VER]' ),
'MQQBrowser' => 'MQQBrowser/[VER]',
'MicroMessenger' => 'MicroMessenger/[VER]',
'baiduboxapp' => 'baiduboxapp/[VER]',
'baidubrowser' => 'baidubrowser/[VER]',
'SamsungBrowser' => 'SamsungBrowser/[VER]',
'Iron' => 'Iron/[VER]',
// @note: Safari 7534.48.3 is actually Version 5.1.
// @note: On BlackBerry the Version is overwriten by the OS.
'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
'Skyfire' => 'Skyfire/[VER]',
'Tizen' => 'Tizen/[VER]',
'Webkit' => 'webkit[ /][VER]',
'PaleMoon' => 'PaleMoon/[VER]',
// Engine
'Gecko' => 'Gecko/[VER]',
'Trident' => 'Trident/[VER]',
'Presto' => 'Presto/[VER]',
'Goanna' => 'Goanna/[VER]',
// OS
'iOS' => ' \bi?OS\b [VER][ ;]{1}',
'Android' => 'Android [VER]',
'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'),
'BREW' => 'BREW [VER]',
'Java' => 'Java/[VER]',
// @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
// @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'),
'Windows Phone' => 'Windows Phone [VER]',
'Windows CE' => 'Windows CE/[VER]',
// http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
'Windows NT' => 'Windows NT [VER]',
'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
);
/**
* Construct an instance of this class.
*
* @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
* If left empty, will use the global _SERVER['HTTP_*'] vars instead.
* @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
* from the $headers array instead.
*/
public function __construct(
array $headers = null,
$userAgent = null
) {
$this->setHttpHeaders($headers);
$this->setUserAgent($userAgent);
}
/**
* Get the current script version.
* This is useful for the demo.php file,
* so people can check on what version they are testing
* for mobile devices.
*
* @return string The version number in semantic version format.
*/
public static function getScriptVersion()
{
return self::VERSION;
}
/**
* Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
*
* @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
* the headers. The default null is left for backwards compatibility.
*/
public function setHttpHeaders($httpHeaders = null)
{
// use global _SERVER if $httpHeaders aren't defined
if (!is_array($httpHeaders) || !count($httpHeaders)) {
$httpHeaders = $_SERVER;
}
// clear existing headers
$this->httpHeaders = array();
// Only save HTTP headers. In PHP land, that means only _SERVER vars that
// start with HTTP_.
foreach ($httpHeaders as $key => $value) {
if (substr($key, 0, 5) === 'HTTP_') {
$this->httpHeaders[$key] = $value;
}
}
// In case we're dealing with CloudFront, we need to know.
$this->setCfHeaders($httpHeaders);
}
/**
* Retrieves the HTTP headers.
*
* @return array
*/
public function getHttpHeaders()
{
return $this->httpHeaders;
}
/**
* Retrieves a particular header. If it doesn't exist, no exception/error is caused.
* Simply null is returned.
*
* @param string $header The name of the header to retrieve. Can be HTTP compliant such as
* "User-Agent" or "X-Device-User-Agent" or can be php-esque with the
* all-caps, HTTP_ prefixed, underscore seperated awesomeness.
*
* @return string|null The value of the header.
*/
public function getHttpHeader($header)
{
// are we using PHP-flavored headers?
if (strpos($header, '_') === false) {
$header = str_replace('-', '_', $header);
$header = strtoupper($header);
}
// test the alternate, too
$altHeader = 'HTTP_' . $header;
//Test both the regular and the HTTP_ prefix
if (isset($this->httpHeaders[$header])) {
return $this->httpHeaders[$header];
} elseif (isset($this->httpHeaders[$altHeader])) {
return $this->httpHeaders[$altHeader];
}
return null;
}
public function getMobileHeaders()
{
return self::$mobileHeaders;
}
/**
* Get all possible HTTP headers that
* can contain the User-Agent string.
*
* @return array List of HTTP headers.
*/
public function getUaHttpHeaders()
{
return self::$uaHttpHeaders;
}
/**
* Set CloudFront headers
* http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
*
* @param array $cfHeaders List of HTTP headers
*
* @return boolean If there were CloudFront headers to be set
*/
public function setCfHeaders($cfHeaders = null) {
// use global _SERVER if $cfHeaders aren't defined
if (!is_array($cfHeaders) || !count($cfHeaders)) {
$cfHeaders = $_SERVER;
}
// clear existing headers
$this->cloudfrontHeaders = array();
// Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
// start with cloudfront-.
$response = false;
foreach ($cfHeaders as $key => $value) {
if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') {
$this->cloudfrontHeaders[strtoupper($key)] = $value;
$response = true;
}
}
return $response;
}
/**
* Retrieves the cloudfront headers.
*
* @return array
*/
public function getCfHeaders()
{
return $this->cloudfrontHeaders;
}
/**
* @param string $userAgent
* @return string
*/
private function prepareUserAgent($userAgent) {
$userAgent = trim($userAgent);
$userAgent = substr($userAgent, 0, 500);
return $userAgent;
}
/**
* Set the User-Agent to be used.
*
* @param string $userAgent The user agent string to set.
*
* @return string|null
*/
public function setUserAgent($userAgent = null)
{
// Invalidate cache due to #375
$this->cache = array();
if (false === empty($userAgent)) {
return $this->userAgent = $this->prepareUserAgent($userAgent);
} else {
$this->userAgent = null;
foreach ($this->getUaHttpHeaders() as $altHeader) {
if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
$this->userAgent .= $this->httpHeaders[$altHeader] . " ";
}
}
if (!empty($this->userAgent)) {
return $this->userAgent = $this->prepareUserAgent($this->userAgent);
}
}
if (count($this->getCfHeaders()) > 0) {
return $this->userAgent = 'Amazon CloudFront';
}
return $this->userAgent = null;
}
/**
* Retrieve the User-Agent.
*
* @return string|null The user agent if it's set.
*/
public function getUserAgent()
{
return $this->userAgent;
}
/**
* Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
* self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
*
* @deprecated since version 2.6.9
*
* @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
* parameter is null which will default to self::DETECTION_TYPE_MOBILE.
*/
public function setDetectionType($type = null)
{
if ($type === null) {
$type = self::DETECTION_TYPE_MOBILE;
}
if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) {
return;
}
$this->detectionType = $type;
}
public function getMatchingRegex()
{
return $this->matchingRegex;
}
public function getMatchesArray()
{
return $this->matchesArray;
}
/**
* Retrieve the list of known phone devices.
*
* @return array List of phone devices.
*/
public static function getPhoneDevices()
{
return self::$phoneDevices;
}
/**
* Retrieve the list of known tablet devices.
*
* @return array List of tablet devices.
*/
public static function getTabletDevices()
{
return self::$tabletDevices;
}
/**
* Alias for getBrowsers() method.
*
* @return array List of user agents.
*/
public static function getUserAgents()
{
return self::getBrowsers();
}
/**
* Retrieve the list of known browsers. Specifically, the user agents.
*
* @return array List of browsers / user agents.
*/
public static function getBrowsers()
{
return self::$browsers;
}
/**
* Retrieve the list of known utilities.
*
* @return array List of utilities.
*/
public static function getUtilities()
{
return self::$utilities;
}
/**
* Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
*
* @deprecated since version 2.6.9
*
* @return array All the rules (but not extended).
*/
public static function getMobileDetectionRules()
{
static $rules;
if (!$rules) {
$rules = array_merge(
self::$phoneDevices,
self::$tabletDevices,
self::$operatingSystems,
self::$browsers
);
}
return $rules;
}
/**
* Method gets the mobile detection rules + utilities.
* The reason this is separate is because utilities rules
* don't necessary imply mobile. This method is used inside
* the new $detect->is('stuff') method.
*
* @deprecated since version 2.6.9
*
* @return array All the rules + extended.
*/
public function getMobileDetectionRulesExtended()
{
static $rules;
if (!$rules) {
// Merge all rules together.
$rules = array_merge(
self::$phoneDevices,
self::$tabletDevices,
self::$operatingSystems,
self::$browsers,
self::$utilities
);
}
return $rules;
}
/**
* Retrieve the current set of rules.
*
* @deprecated since version 2.6.9
*
* @return array
*/
public function getRules()
{
if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
return self::getMobileDetectionRulesExtended();
} else {
return self::getMobileDetectionRules();
}
}
/**
* Retrieve the list of mobile operating systems.
*
* @return array The list of mobile operating systems.
*/
public static function getOperatingSystems()
{
return self::$operatingSystems;
}
/**
* Check the HTTP headers for signs of mobile.
* This is the fastest mobile check possible; it's used
* inside isMobile() method.
*
* @return bool
*/
public function checkHttpHeadersForMobile()
{
foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
if (isset($this->httpHeaders[$mobileHeader])) {
if (is_array($matchType['matches'])) {
foreach ($matchType['matches'] as $_match) {
if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) {
return true;
}
}
return false;
} else {
return true;
}
}
}
return false;
}
/**
* Magic overloading method.
*
* @method boolean is[...]()
* @param string $name
* @param array $arguments
* @return mixed
* @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
*/
public function __call($name, $arguments)
{
// make sure the name starts with 'is', otherwise
if (substr($name, 0, 2) !== 'is') {
throw new BadMethodCallException("No such method exists: $name");
}
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
$key = substr($name, 2);
return $this->matchUAAgainstKey($key);
}
/**
* Find a detection rule that matches the current User-agent.
*
* @param null $userAgent deprecated
* @return boolean
*/
protected function matchDetectionRulesAgainstUA($userAgent = null)
{
// Begin general search.
foreach ($this->getRules() as $_regex) {
if (empty($_regex)) {
continue;
}
if ($this->match($_regex, $userAgent)) {
return true;
}
}
return false;
}
/**
* Search for a certain key in the rules array.
* If the key is found then try to match the corresponding
* regex against the User-Agent.
*
* @param string $key
*
* @return boolean
*/
protected function matchUAAgainstKey($key)
{
// Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
$key = strtolower($key);
if (false === isset($this->cache[$key])) {
// change the keys to lower case
$_rules = array_change_key_case($this->getRules());
if (false === empty($_rules[$key])) {
$this->cache[$key] = $this->match($_rules[$key]);
}
if (false === isset($this->cache[$key])) {
$this->cache[$key] = false;
}
}
return $this->cache[$key];
}
/**
* Check if the device is mobile.
* Returns true if any type of mobile device detected, including special ones
* @param null $userAgent deprecated
* @param null $httpHeaders deprecated
* @return bool
*/
public function isMobile($userAgent = null, $httpHeaders = null)
{
if ($httpHeaders) {
$this->setHttpHeaders($httpHeaders);
}
if ($userAgent) {
$this->setUserAgent($userAgent);
}
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
if ($this->getUserAgent() === 'Amazon CloudFront') {
$cfHeaders = $this->getCfHeaders();
if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
return true;
}
}
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
if ($this->checkHttpHeadersForMobile()) {
return true;
} else {
return $this->matchDetectionRulesAgainstUA();
}
}
/**
* Check if the device is a tablet.
* Return true if any type of tablet device is detected.
*
* @param string $userAgent deprecated
* @param array $httpHeaders deprecated
* @return bool
*/
public function isTablet($userAgent = null, $httpHeaders = null)
{
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
if ($this->getUserAgent() === 'Amazon CloudFront') {
$cfHeaders = $this->getCfHeaders();
if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') {
return true;
}
}
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
foreach (self::$tabletDevices as $_regex) {
if ($this->match($_regex, $userAgent)) {
return true;
}
}
return false;
}
/**
* This method checks for a certain property in the
* userAgent.
* @todo: The httpHeaders part is not yet used.
*
* @param string $key
* @param string $userAgent deprecated
* @param string $httpHeaders deprecated
* @return bool|int|null
*/
public function is($key, $userAgent = null, $httpHeaders = null)
{
// Set the UA and HTTP headers only if needed (eg. batch mode).
if ($httpHeaders) {
$this->setHttpHeaders($httpHeaders);
}
if ($userAgent) {
$this->setUserAgent($userAgent);
}
$this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
return $this->matchUAAgainstKey($key);
}
/**
* Some detection rules are relative (not standard),
* because of the diversity of devices, vendors and
* their conventions in representing the User-Agent or
* the HTTP headers.
*
* This method will be used to check custom regexes against
* the User-Agent string.
*
* @param $regex
* @param string $userAgent
* @return bool
*
* @todo: search in the HTTP headers too.
*/
public function match($regex, $userAgent = null)
{
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
// If positive match is found, store the results for debug.
if ($match) {
$this->matchingRegex = $regex;
$this->matchesArray = $matches;
}
return $match;
}
/**
* Get the properties array.
*
* @return array
*/
public static function getProperties()
{
return self::$properties;
}
/**
* Prepare the version number.
*
* @todo Remove the error supression from str_replace() call.
*
* @param string $ver The string version, like "2.6.21.2152";
*
* @return float
*/
public function prepareVersionNo($ver)
{
$ver = str_replace(array('_', ' ', '/'), '.', $ver);
$arrVer = explode('.', $ver, 2);
if (isset($arrVer[1])) {
$arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
}
return (float) implode('.', $arrVer);
}
/**
* Check the version of the given property in the User-Agent.
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
*
* @param string $propertyName The name of the property. See self::getProperties() array
* keys for all possible properties.
* @param string $type Either self::VERSION_TYPE_STRING to get a string value or
* self::VERSION_TYPE_FLOAT indicating a float value. This parameter
* is optional and defaults to self::VERSION_TYPE_STRING. Passing an
* invalid parameter will default to the this type as well.
*
* @return string|float The version of the property we are trying to extract.
*/
public function version($propertyName, $type = self::VERSION_TYPE_STRING)
{
if (empty($propertyName)) {
return false;
}
// set the $type to the default if we don't recognize the type
if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) {
$type = self::VERSION_TYPE_STRING;
}
$properties = self::getProperties();
// Check if the property exists in the properties array.
if (true === isset($properties[$propertyName])) {
// Prepare the pattern to be matched.
// Make sure we always deal with an array (string is converted).
$properties[$propertyName] = (array) $properties[$propertyName];
foreach ($properties[$propertyName] as $propertyMatchString) {
$propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
// Identify and extract the version.
preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match);
if (false === empty($match[1])) {
$version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]);
return $version;
}
}
}
return false;
}
/**
* Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
*
* @return string One of the self::MOBILE_GRADE_* constants.
*/
public function mobileGrade()
{
$isMobile = $this->isMobile();
if (
// Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0)
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 ||
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 ||
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 ||
// Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
// Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
// Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
// Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) ||
// Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8)
$this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 ||
// Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
$this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 ||
// Blackberry Playbook (1.0-2.0) - Tested on PlayBook
$this->match('Playbook.*Tablet') ||
// Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) ||
// Palm WebOS 3.0 - Tested on HP TouchPad
$this->match('hp.*TouchPad') ||
// Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) ||
// Chrome for Android - Tested on Android 4.0, 4.1 device
( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) ||
// Skyfire 4.1 - Tested on Android 2.3 device
( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
// Opera Mobile 11.5-12: Tested on Android 2.3
( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) ||
// Meego 1.2 - Tested on Nokia 950 and N9
$this->is('MeeGoOS') ||
// Tizen (pre-release) - Tested on early hardware
$this->is('Tizen') ||
// Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
// @todo: more tests here!
$this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 ||
// UC Browser - Tested on Android 2.3 device
( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
// Kindle 3 and Fire - Tested on the built-in WebKit browser for each
( $this->match('Kindle Fire') ||
$this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) ||
// Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
$this->is('AndroidOS') && $this->is('NookTablet') ||
// Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
$this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile ||
// Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
$this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile ||
// Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
$this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile ||
// Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
$this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile ||
// Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
$this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile
){
return self::MOBILE_GRADE_A;
}
if (
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 ||
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 ||
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 ||
// Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
$this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 ||
//Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 &&
($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) ||
// Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
$this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
// @todo: report this (tested on Nokia N71)
$this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS')
){
return self::MOBILE_GRADE_B;
}
if (
// Blackberry 4.x - Tested on the Curve 8330
$this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 ||
// Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
$this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 ||
// Tested on original iPhone (3.1), iPhone 3 (3.2)
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 ||
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 ||
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 ||
// Internet Explorer 7 and older - Tested on Windows XP
$this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile
){
return self::MOBILE_GRADE_C;
}
// All older smartphone platforms and featurephones - Any device that doesn't support media queries
// will receive the basic, C grade experience.
return self::MOBILE_GRADE_C;
}
}
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
}
<?php
namespace App\Providers;
use Illuminate\Contracts\Auth\Access\Gate as GateContract;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any application authentication / authorization services.
*
* @param \Illuminate\Contracts\Auth\Access\Gate $gate
* @return void
*/
public function boot(GateContract $gate)
{
$this->registerPolicies($gate);
//
}
}
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'App\Events\SomeEvent' => [
'App\Listeners\EventListener',
],
];
/**
* Register any other events for your application.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
//
}
}
<?php
namespace App\Providers;
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to the controller routes in your routes file.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'App\Http\Controllers';
/**
* Define your route model bindings, pattern filters, etc.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function boot(Router $router)
{
//
parent::boot($router);
}
/**
* Define the routes for the application.
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
});
}
}
<?php
namespace App\Providers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\ServiceProvider;
class TranslationServiceProvider extends ServiceProvider
{
/**
* The path to the current lang files.
*
* @var string
*/
protected $langPath;
/**
* Create a new service provider instance.
*
* @return void
*/
public function __construct()
{
$this->langPath = resource_path('lang/'.App::getLocale());
}
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
Cache::rememberForever('translations', function () {
return collect(File::allFiles($this->langPath))->flatMap(function ($file) {
return [
($translation = $file->getBasename('.php')) => trans($translation),
];
})->toJson();
});
}
}
\ No newline at end of file
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;
class Room extends Model
{
use Authenticatable, Authorizable;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'rooms';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name', 'pin', 'layout'];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = ['pin', 'layout'];
}
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['name', 'login', 'phone', 'password'];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = ['password', 'remember_token'];
}
<?php
namespace App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
class Vms {
var $password;
var $port;
var $host;
var $fp = null ;
var $iRetryCurrentNumber = 0 ;
var $iRetryMaxNumber = 100 ;
function __construct()
{
$this->host = config('vms.host'); // "127.0.0.1";
$this->port = config('vms.port'); // "8021";
$this->password = config('vms.password');// "mteam";
return $this ;
}
private function event_socket_create() {
try {
$this->fp = fsockopen($this->host, $this->port, $errno, $errdesc);
} catch (Exception $e) {
}
if (!$this->fp) {
if( $this->iRetryCurrentNumber < $this->iRetryMaxNumber ){
$this->iRetryCurrentNumber++ ;
sleep(1);
return $this->event_socket_create() ;
}else{
die("Connection to $this->host failed");
}
}
$this->iRetryCurrentNumber = 0 ;
socket_set_blocking($this->fp,false);
if ($this->fp) {
while (!feof($this->fp)) {
$buffer = fgets($this->fp, 1024);
usleep(100); //allow time for reponse
if (trim($buffer) == "Content-Type: auth/request") {
fputs($this->fp, "auth $this->password\n\n");
break;
}
}
return $this->fp;
}else {
return false;
}
}
public function event_socket_close() {
$this->fp->close();
}
public function eRequest( $cmd ) {
if( is_null( $this->fp ) ){
$this->event_socket_create();
}
if ($this->fp) {
//var_dump($cmd);
fputs($this->fp, $cmd."\n\n");
usleep(100); //allow time for response
$response = '';
$length = 0;
$x = 0;
while (!feof($this->fp) )
{
$x++;
usleep(10);
$theNewData = stream_get_line($this->fp, 4096, "\n");
if ($length > 0) {
$response .= $theNewData . "\n";
}
if ($length == 0 && strpos($theNewData, 'Content-Length:') !== false) {
$length = (int)str_replace('Content-Length: ', '', $theNewData);
}
if ($length > 0 && strlen($response) >= $length) {
break;
}
if ($x > 10000) break;
}
$this->fp = null;
// If a JSON response, process the event, otherwise return the raw result
if ((strpos($response, '{') === 0) || (substr($response, 0,2) == '[{')) {
$response = $this->getJsonReponseClean( $response ) ;
if( is_array( $response )){
$myFSEvent = new FreeSwitchEvent();
$myFSEvent = $myFSEvent->loadFromArray( $response ) ;
$this->SendFreeSwitchEvent( $myFSEvent );
}
}else{
return $response;
}
}else {
echo "no handle";
}
}
/*
* Send FreeSwitchEvent to ...
*/
private function SendFreeSwitchEvent( $_FreeSwitchEvent ){
if( !is_null( $_FreeSwitchEvent ) ){
var_dump( $_FreeSwitchEvent ) ;
}
return true ;
}
public function isConfStreaming($r){
$arConf = $this->getConferenceArray($r);
$stream = false;
if( empty($arConf["members"]) ){ return false; }
foreach( $arConf["members"] as $mbr ){
if(!empty($mbr["type"])){
if( $mbr["type"] == 'recording_node' ){
if( substr($mbr["record_path"],0,4) == 'rtmp' ){
$stream = true;
}
}
}
}
return $stream;
}
public function getConferenceArray($r){
$response = $this->eRequest( "api conference ".$r." json_list" );
if( substr($response,0,4) == "-ERR" ) { return "Server error"; }
if( empty($response)) { return "Server response is empty";}
$arRespArRooms = json_decode($response."}]",true);
return $arRespArRooms[0];
}
public function getConfNumberInfos($i){
if( empty($i["room"]) ){ return array("result"=>"error", "msg"=>"No room"); }
$arRespArRooms = $this->getConferenceArray($i["room"]);
$mmbrs = 0;
if( empty($arRespArRooms["members"]) ){ return array("result"=>"error", "msg"=>"No room"); }
foreach( $arRespArRooms["members"] as $mbr ){
if(!empty($mbr["caller_id_name"])){
if( $mbr["caller_id_name"] != "Admin"){
$mmbrs++;
}
}
//"conference_name"
}
return array(
"conference" => $arRespArRooms["conference_name"],
"mcount" => $mmbrs,
"conference_uuid" => $arRespArRooms["conference_uuid"],
"msgs" => 10,
);
}
public function getAllWssUsers(){
$usResponse = $this->eRequest( "api verto status" );
$arUsLines = explode("\n",$usResponse);
$arUsers = array();
$uCols = array();
foreach( $arUsLines as $users ){
$arVals = preg_match("/::(\d{3,})\@\d{1,2}.*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):\d{3,5}/",$users,$matches);
//var_dump( $matches );
if( !empty($matches) ){
$arUsers[$matches[1]] = $matches;
}
//$arLine = explode(" ",$users);
//if($arLine[""])
}
return $arUsers;
}
public function getChannelsInfo($room=false){
$usResponse = $this->eRequest( "api show channels" );
$arUsLines = explode("\n",$usResponse);
$arChannels = array();
$uCols = array();
foreach( $arUsLines as $chans ){
$arLine = explode(",",$chans);
if( count($arLine) > 1 ){
if( $arLine[0] == "uuid"){
foreach( $arLine as $cl ){
$uCols[] = $cl;
}
} else {
$nChan = array();
foreach( $arLine as $uKey=>$uLine ){
$nChan[$uCols[$uKey]] = $uLine;
}
if( (!empty($room)) && ($nChan["dest"] != $room) && ( $nChan["application_data"] != $room) ) { continue; }
$arChannels[$nChan["uuid"]] = $nChan;
}
}
}
return $arChannels;
}
public function getOnlineUsers(){
$usResponse = $this->eRequest( "api show registrations" );
$arUsLines = explode("\n",$usResponse);
$arOnlines = array();
$uCols = array();
foreach( $arUsLines as $users ){
if( strlen($users) < 20 ){ continue; }
$arLine = explode(",",$users);
if( $arLine[0] == "reg_user"){
foreach( $arLine as $cl ){
$uCols[] = $cl;
}
} else {
$nUser = array();
foreach( $arLine as $uKey=>$uLine ){
$nUser[$uCols[$uKey]] = $uLine;
}
$arOnlines[$nUser["reg_user"]] = $nUser;
}
}
return $arOnlines;
}
public function getAllUsersByRooms(){
$usResponse = $this->getAllUsers();
$rUsrs = array();
foreach($usResponse as $usr) {
$rUsrs[$usr["callgroup"]][] = $usr;
}
return $rUsrs;
}
public function getOneUserInfo($num){
if(empty($num)){
return false;
}
$arsUser = DB::table('clients')->where('number', $num)->get();
if(empty($arsUser)){
return false;
}
$arUser = json_decode(json_encode($arsUser[0]),true);
$users_path = config('vms.users_path');
if( !file_exists( $users_path ."vmj_".$num.".xml") ){
return false;
}
$arXmlFileUser = $this->XML2JSON( $users_path."vmj_".$num.".xml" );
if(empty($arXmlFileUser)){
return false;
}
$arUser["peer"] = self::getUserDataFromXML($arXmlFileUser);
return $arUser;
}
public function getAllUsers($room=false){
//$arWssUsers = $this->getAllWssUsers();
$dbUsers = DB::select('select * from clients');
$ardbUsers = array();
$ardbLoginUsers = array();
foreach($dbUsers as $dbusr){ $ardbUsers[] = $dbusr->number; $ardbLoginUsers[$dbusr->number] = $dbusr; } //->login
$usResponse = $this->eRequest( "api list_users" );
$arUsLines = explode("\n",$usResponse);
$arUsers = array();
$uCols = array();
foreach( $arUsLines as $users ){
$arLine = explode("|",$users);
if( count($arLine) > 1 ){
if( $arLine[0] == "userid"){
foreach( $arLine as $cl ){
$uCols[] = $cl;
}
} else {
$nUser = array();
foreach( $arLine as $uKey=>$uLine ){
/*if( !empty($arWssUsers[1]) ){
if($arWssUsers[1] == $uLine["userid"]){
$uLine["contact"] = "wss://".$arWssUsers[2];
}
}*/
$nUser[$uCols[$uKey]] = $uLine;
}
if(!empty($room)) { if( $nUser["callgroup"] != $room) { continue; }}
if($nUser["userid"]=="default") { continue; }
if( in_array($nUser["userid"],$ardbUsers) ){
$nUser["peertype"]='webrtc';
} else {
$nUser["peertype"]='sip';
}
if( !empty($ardbLoginUsers[$nUser["userid"]]) ){
$nUser["login"]=$ardbLoginUsers[$nUser["userid"]]->login;
$nUser["name"]=$ardbLoginUsers[$nUser["userid"]]->name;
$nUser["bandwidth_in"]=$ardbLoginUsers[$nUser["userid"]]->bandwidth_in;
$nUser["bandwidth_out"]=$ardbLoginUsers[$nUser["userid"]]->bandwidth_out;
} else {
$nUser["name"]= (!empty($nUser["effective_caller_id_name"])) ? $nUser["effective_caller_id_name"] : "SomeOne";
}
$arUsers[$nUser["userid"]] = $nUser;
}
}
}
return $arUsers;
}
public function getOneRoom($r){
$rPath = config('vms.rooms_path');
$room_file = $rPath . "vmj_" . $r . ".xml";
$arRoom = $this->XML2JSON( $room_file );
if(!$arRoom){ return false;}
return $this->getRoomData($arRoom);
}
public function getActiveItemData($d){
if( (empty($d['room']) )){ return "No Room";}
if( $d['lid']>-1 ){ $lid = $d['lid']; } else { return "No Layer id"; }
$response = $this->eRequest( "api conference " . $d["room"] . " json_list");
if( substr($response,0,4) == "-ERR" ) { return "Server error"; }
if( empty($response)) { return "Server response is empty";}
$arRespArRooms = json_decode($response."}]",true);
$arRespArRoom = $arRespArRooms[0];
foreach( $arRespArRoom["members"] as $mbr ){
if( isset($mbr["video_layer_id"]) ){
if( $mbr["video_layer_id"] == $lid ){
return $mbr;
}
}
}
return "No found Layer id - ".$lid;
}
public function getActiveRoomData($room){
if( empty( $room )) { return []; }
$response = $this->eRequest( "api conference ".$room." json_list" );
if( substr($response,0,4) == "-ERR" ) { return []; }
if( empty($response)) { return [];}
$arRespArRooms = json_decode($response."}]",true);
$arRespArRoom = $arRespArRooms[0];
$arChans = $this->getChannelsInfo($room);
$arOnlineSips = $this->getOnlineUsers();
$arRoomUsers = $this->getAllUsers($room);
$arRoomAllUsers = [];
$arRoomOFFUsers = [];
$arRoomVideoUsers = [];
$arRoomVoiceUsers = [];
$arRespArRoom["members_old"] = $arRespArRoom["members"];
if(!empty($arRespArRoom["members"])){
foreach( $arRespArRoom["members"] as $mKey => $mmbrs ){
if( $mmbrs["type"] == "recording_node"){
if( substr($mmbrs["record_path"],-6) == "stream" ){
$arRespArRoom["streaming"] = $mmbrs;
} else {
$arRespArRoom["recordings"] = $mmbrs;
}
unset($arRespArRoom["members"][$mKey]);
continue;
}
if(empty($mmbrs["uuid"])){
unset($arRespArRoom["members"][$mKey]);
continue;
}
if(($mmbrs["caller_id_name"] == "Admin")){
unset($arRespArRoom["members"][$mKey]);
continue;
}
/*if( isset($mmbrs["video_layer_id"]) ){
if(($mmbrs["video_layer_id"] == "-1") && $mmbrs["flags"]["hold"] == false){
unset($arRespArRoom["members"][$mKey]);
continue;
}
}*/
if( (!empty($arChans[$mmbrs["uuid"]])) ){
/*if( $mmbrs["caller_id_name"] == "Outbound Call" ){
$mmbrs["caller_id_name"] = $arRoomUsers[$mmbrs["caller_id_number"]]["effective_caller_id_name"];
}
$arRespArRoom["members"][$mKey]["fullname"] = $mmbrs["caller_id_name"];
$arRespArRoom["members"][$mKey]["more"] = $arChans[$mmbrs["uuid"]];
$mmbrs["fullname"] = $mmbrs["caller_id_name"];
$mmbrs["more"] = $arChans[$mmbrs["uuid"]];
*/
unset($arRoomUsers[$mmbrs["caller_id_number"]]);
}
if( ($mmbrs["video_layer_id"] == "-1") && ($mmbrs["flags"]["hold"] == false) ){
if( $mmbrs["caller_id_name"] == "Outbound Call" ){
$mmbrs["caller_id_name"] = $arRoomUsers[$mmbrs["caller_id_number"]]["effective_caller_id_name"];
}
$mmbrs["caller_id_name"] = '<i class="fa fa-microphone"></i> '.$mmbrs["caller_id_name"];
$mmbrs["calltype"] = 'audio';
$mmbrs["fullname"] = $mmbrs["caller_id_name"];
if( !empty($arChans[$mmbrs["uuid"]]) ){
$mmbrs["more"] = $arChans[$mmbrs["uuid"]];
}
$arRoomVoiceUsers[] = $mmbrs;
unset($arRespArRoom["members"][$mKey]);
continue;
} else {
if( $mmbrs["caller_id_name"] == "Outbound Call" ){
if(!empty($arRoomUsers[$mmbrs["caller_id_number"]])){
$mmbrs["caller_id_name"] = $arRoomUsers[$mmbrs["caller_id_number"]]["effective_caller_id_name"];
}
}
$mmbrs["caller_id_name"] = '<i class="fa fa-video-camera"></i> '.$mmbrs["caller_id_name"];
$mmbrs["calltype"] = 'video';
$mmbrs["fullname"] = $mmbrs["caller_id_name"];
$mmbrs["more"] = ( !empty($arChans[$mmbrs["uuid"]]) ) ? $arChans[$mmbrs["uuid"]] : [];
$arRoomVideoUsers[] = $mmbrs;
unset($arRespArRoom["members"][$mKey]);
continue;
}
}
} else {
$arRespArRoom["conference"] = 'offline';
}
foreach( $arRoomUsers as $uKey=>$usr ){
if( !empty($arOnlineSips[$usr["userid"]]) ){
$usr["network_ip"] = $arOnlineSips[$usr["userid"]]["network_ip"];
$usr["network_port"] = $arOnlineSips[$usr["userid"]]["network_port"];
$arRoomAllUsers[] = $usr;
} else {
$arRoomOFFUsers[] = $usr;
}
/**if( substr($usr["contact"],0,5) == "error" ){
$arRoomOFFUsers[] = $usr;
} else {
// $arRoomUsers
unset($arRoomUsers[$uKey]);
} */
}
$arRoomAllUsers = array_merge_recursive($arRoomAllUsers,$arRoomOFFUsers);
$arRespArRoom["members"] = array_merge_recursive($arRoomVideoUsers,$arRoomVoiceUsers);
$roomData = $this->getOneRoom($room);
$roomProfile = $this->getOneProfile( $roomData["profile"] );
//$room_currlayout_name = (!empty($arRespArRoom["current_video_layout_name"])) ? $arRespArRoom["current_video_layout_name"] : "";
$room_currlayout_name = (!empty($arRespArRoom["canvases"][0]["vlayout_name"])) ? $arRespArRoom["canvases"][0]["vlayout_name"] : "";
$room_layout_name = ((empty($room_currlayout_name))&&(!empty($roomProfile["video-layout-name"]))) ? $roomProfile["video-layout-name"] : $room_currlayout_name;
$roomLayout = $this->get_one_layout( $room_layout_name );
//$roomLayout = $this->get_one_layout( $roomProfile["video-layout-name"] );
$arRespArRoom["data"] = $roomData;
$arRespArRoom["profile"] = $roomProfile;
$arRespArRoom["video-layout"] = $roomLayout;
$arRespArRoom["channels"] = $arChans; //$arRoomUsers;
$arRespArRoom["offline_members"] = $arRoomAllUsers; //$arRoomUsers;
//$recs_path = $rPath = config('vms.records_path');
return $arRespArRoom;
}
public function list_recordings($i){
if( empty($i["room"]) ){ return ""; }
$room = $i["room"];
$recs_path = $rPath = config('vms.records_path');
$files = array_diff(scandir($recs_path), array('.', '..'));
if( empty($files) ) {return "";}
$elems = array();
foreach( $files as $recf ){
$rl = strlen($room);
if( substr($recf,0,$rl) == $room ){
$elems[] = array("filename"=>$recf, "size"=>filesize($recs_path.$recf));
}
}
return $elems;
}
public function getUserPass($i){
if( empty($i["number"]) ) { return false; }
$num = $i["number"];
$users_path = config('vms.users_path');
if( file_exists($users_path."vmj_".$num.".xml") ){
$arUser = $this->XML2JSON( $users_path."vmj_".$num.".xml" );
if(empty($arUser)){ return false; }
$elR = self::getUserDataFromXML($arUser);
if( !empty($elR["password"]) ){
return $elR["password"];
}
} else {
return false;
}
}
public function removeUser($num){
$users_path = config('vms.users_path');
if( file_exists($users_path."vmj_".$num.".xml") ){
unlink( $users_path."vmj_".$num.".xml" );
$response = $this->eRequest( "api reloadxml" );
DB::table('clients')->where('number',$num)->delete();
return "ok";
}
return $num." - file is not found. (".$users_path."vmj_".$num.".xml)";
}
public function changeProfileLayout($i){
if( (empty($i["room"])) || (empty($i["layout"]))){ return array("result"=>"error","msg"=>"Layout or Room is empty");}
$arRoom = $this->getOneRoom($i["room"]);
return array("result"=>"ok","msg"=>$arRoom);
if( !empty($arRoom["conference"])){
//$arProf = getOneProfile($pr)
//$prof_path = config('vms.profiles_path');
}
}
public function getOneProfile($pr){
$prof_path = config('vms.profiles_path');
if( file_exists($prof_path."vmj_".$pr.".xml") ){
$arProfile = $this->XML2JSON( $prof_path."vmj_".$pr.".xml" );
if(empty($arProfile)){ return false; }
return $this->getProfileData($arProfile);
} else {
return false;
}
}
public function getAllProfiles(){
$prof_path = config('vms.profiles_path');
$files = array_diff(scandir($prof_path), array('.', '..'));
if( empty($files) ) {return "";}
$elems = array();
foreach( $files as $xmlf ){
$arProfile = $this->XML2JSON( $prof_path.$xmlf );
//var_dump($arProfile);
if(!$arProfile){ continue; }
$elR = $this->getProfileData($arProfile);
$elems[$elR["name"]] = $elR;
}
return $elems;
}
public function getNewRoomNumberByMinMax($min,$max){
$rPath = config('vms.rooms_path');
$files = array_diff(scandir($rPath), array('.', '..'));
if( empty($files) ) {return "";}
$elems = array();
foreach( $files as $xmlf ){
$arRoom = $this->XML2JSON( $rPath.$xmlf );
if(!$arRoom){ continue; }
$elR = $this->getRoomData($arRoom);
if( ($elR["number"]>=$min) && ($elR["number"]<=$max) ){
$elems[$elR["number"]] = $elR["number"];
}
}
$lastNum = max(array_keys($elems));
return $lastNum + 1;
}
public function getAllRoomsArray(){
$rPath = config('vms.rooms_path');
$files = array_diff(scandir($rPath), array('.', '..'));
if( empty($files) ) {return "";}
$elems = array();
foreach( $files as $xmlf ){
$arRoom = $this->XML2JSON( $rPath.$xmlf );
if(!$arRoom){ continue; }
$elR = $this->getRoomData($arRoom);
$elems[$elR["number"]] = $elR["number"];
}
return $elems;
}
public function getAllRooms(){
$rPath = config('vms.rooms_path');
$arDbRooms = collect(DB::table('rooms')->get())->keyBy('number');
// TODO TO DO DOING
//$arUsrs = $this->getAllUsersByRooms();
$arUsrs = $this->getAllUsers();
$files = array_diff(scandir($rPath), array('.', '..'));
if( empty($files) ) {return "";}
$elems = array();
foreach( $files as $xmlf ){
$arRoom = $this->XML2JSON( $rPath.$xmlf );
if(!$arRoom){ continue; }
$elR = $this->getRoomData($arRoom);
$arRoomUserNums = (!empty($arDbRooms[$elR["number"]]->users) ) ? json_decode($arDbRooms[$elR["number"]]->users) : [];
$roomUsers = [];
$roomUserNames = [];
foreach($arRoomUserNums as $rnm ){
if( !empty($arUsrs[$rnm]) ){
$roomUsers[] = $arUsrs[$rnm];
$roomUserNames[$rnm] = $arUsrs[$rnm]["name"];
}
}
$elR["userscount"] = (!empty($arRoomUserNums)) ? count($arRoomUserNums) : 0;
$elR["users"] = (!empty($arDbRooms[$elR["number"]])) ? implode(",",$arRoomUserNums) : 0;
$elR["usernames"] = $roomUserNames;
$elR["arusers"] = $roomUsers ;
$elems[$elR["number"]] = $elR;
}
return $elems;
}
public function getAllActiveRooms(){
// Get Rooms Statuses in System
$response = $this->eRequest( "api conference json_list" );
if( empty($response)) { return "";}
$arRespRooms = json_decode($response."}]",true);
$arActiveRooms = array();
foreach( $arRespRooms as $aRoom ){
$arActiveRooms[$aRoom["conference_name"]] = $aRoom;
}
return $arActiveRooms;
}
public static function getUserDataFromXML($arUser){
$r = array();
$r["number"] = $arUser["user"]["id"];
foreach( $arUser["user"]["params"]["param"] as $prs ){
if( $prs["name"] == "password" ){
$r["password"] = $prs["value"];
}
}
foreach( $arUser["user"]["variables"]["variable"] as $vars ){
if( $vars["name"] == "callgroup" ){
$r["room"] = $vars["value"];
}
if( $vars["name"] == "effective_caller_id_name" ){
$r["name"] = $vars["value"];
}
}
return $r;
}
public function getProfileData($arProf){
$p = array();
$p["name"] = $arProf["name"];
foreach ( $arProf["param"] as $prm ){
if( !empty($prm["name"]) ){
$p[$prm["name"]] = $prm["value"];
}
}
return $p;
}
public static function getRoomData($arRoom){
$r = array();
$r["name"] = $arRoom["extension"]["name"];
$numPregs = preg_match("/[0-9]{1,}/",$arRoom["extension"]["condition"]["expression"],$nummatch);
$r["number"] = $nummatch[0]; //substr($arRoom["extension"]["condition"]["expression"],1,-1);
foreach ( $arRoom["extension"]["condition"]["action"] as $a ){
//var_dump($a);
if( !empty($a["data"]) ){
if( substr($a["data"],0,17) == "video_banner_text" ){
$tSts = substr($a["data"],18);
$arBr = explode("}",$tSts);
$arBanner = explode(",",substr($arBr[0],1));
$r["subtitle_text"] = $arBr[1];
$r["subtitle"] = array();
foreach( $arBanner as $bv ){
$arb = explode("=",$bv);
$r["subtitle"][$arb[0]] = $arb[1];
}
}
if( $a["application"] == "conference" ){
$r["profile"] = substr($a["data"],7);
}
if( substr($a["data"],0,23) == "conference_member_flags" ){
$r["member_flags"] = substr($a["data"],24);
}
}
}
return $r;
}
private static function getActiveRooms(){
//conference json_list
}
/*
Metod: Save or create USER
Usage: saveUser([num,password,name,<room>])
*/
public function saveUser($arPeer){
/*
num
password
name
room
*/
if( empty($arPeer["num"]) || empty($arPeer["password"]) || empty($arPeer["name"])){
return false;
}
if( $arPeer["nopass"] ){
$uPass = $arPeer["password"];
}
elseif( !empty($arPeer["typeuser"]) ) {
if($arPeer["typeuser"]=="webrtc") {
$webrtc = true;
$uPass = md5($arPeer["password"]);
} else {
$uPass = $arPeer["password"];
}
} else {
$uPass = $arPeer["password"];
}
if( empty($arPeer["room"]) ) { $pRoom = '7777';} else { $pRoom = $arPeer["room"]; }
$db_bandwidth_in = '';
$db_bandwidth_out = '';
if( !empty($arPeer["ptzurl"]) ) { $ptzurl = $arPeer["ptzurl"];} else { $ptzurl = ""; }
if( !empty($arPeer["bandwidth_in"]) ) { $db_bandwidth_in = $arPeer["bandwidth_in"]; $bandwidth_in = '<variable name="rtp_video_max_bandwidth_in" value="'.$arPeer["bandwidth_in"].'kb"/>';} else { $bandwidth_in = ""; }
if( !empty($arPeer["bandwidth_out"]) ) { $db_bandwidth_out = $arPeer["bandwidth_out"]; $bandwidth_out = '<variable name="rtp_video_max_bandwidth_out" value="'.$arPeer["bandwidth_out"].'kb"/>';} else { $bandwidth_out = ""; }
/*
<variable name="rtp_video_max_bandwidth_in" value="20kb"/>
<variable name="rtp_video_max_bandwidth_out" value="20kb"/>
*/
$peer_temp = '<include>
<user id="'.$arPeer["num"].'">
<params>
<param name="password" value="'.$uPass.'"/>
<param name="vm-password" value="'.$uPass.'"/>
</params>
<variables>
'.$bandwidth_in .'
'.$bandwidth_out .'
<variable name="toll_allow" value="domestic,international,local"/>
<variable name="accountcode" value="'.$arPeer["num"].'"/>
<variable name="user_context" value="default"/>
<variable name="effective_caller_id_name" value="'.$arPeer["name"].'"/>
<variable name="effective_caller_id_number" value="'.$arPeer["num"].'"/>
<variable name="outbound_caller_id_name" value="'.$arPeer["name"].'"/>
<variable name="outbound_caller_id_number" value="'.$arPeer["num"].'"/>
<variable name="callgroup" value="'.$pRoom.'"/>
<variable name="ptzurl" value="'.$ptzurl.'"/>
</variables>
</user>
</include>';
if( $this->save_user_file($arPeer["num"], $peer_temp) ){
$response = $this->eRequest( "api reloadxml" );
if($arPeer["typeuser"]=="webrtc"){
$jsonRoomUsers = DB::table('rooms')->where('number', $pRoom)->value('users');
if(!empty($jsonRoomUsers)){
$arRoomUsers = json_decode($jsonRoomUsers);
if(empty($arRoomUsers[$arPeer["num"]])){
$arRoomUsers[] = $arPeer["num"];
$rusrEditData['users'] = json_encode( $arRoomUsers );
DB::table('rooms')->where('number', $pRoom)->update($rusrEditData);
}
}
$params_Save_User = [
'number' => $arPeer["num"],
'login' => $arPeer["login"],
'password' => $uPass,
'name' => $arPeer["name"],
'bandwidth_in' => $db_bandwidth_in,
'bandwidth_out' => $db_bandwidth_out,
'typeuser' => $arPeer["typeuser"],
//'room' =>$pRoom
];
$myuid = DB::table('clients')->where('number', $arPeer["num"])->value('id');
if(!empty($myuid)){
$updans = DB::table('clients')->where('id', $myuid)->update($params_Save_User);
$anstype = 'upd';
} else {
$uid = DB::table('clients')->insertGetId($params_Save_User);
$anstype = 'ins';
}
}
$arPeer["prms"] = $params_Save_User;
$arPeer["type"] = $anstype;
return $arPeer;
}
}
public function saveRoom( $r ){
/*
saveRoom(
number | 7777
name | vMajlis
member_flags | join-vid-floor
conf_profile | 'video-mcu-stereo'
)
*/
if( empty($r["number"]) || empty($r["name"]) ) { return "Room name is empty"; }
if( empty($r["name"])) { $r["name"] = 'vMajlis-'.random_int(1234, 8899); }
if( empty($r["conf_profile"]) ){ $r["conf_profile"] = 'vmj_default_profile'; } //video-mcu-stereo
$room_xml = $this->createRoomXml( $r );
if( $this->save_room_file($r["number"], $room_xml) ){
if( !empty($r["roomusers"])) {
//rooms
/*
id int(10) unsigned Автоматическое приращение
name varchar(255)
number varchar(10)
profile varchar(100)
users text
desc text
pin varchar(255)
layout varchar(255)
created_at timestamp [0000-00-00 00:00:00]
updated_at timestamp [0000-00-00 00:00:00]
*/
$roomData = [
'name' => $r["name"],
'number' => $r["number"],
'users' => (!empty($r["roomusers"])) ? json_encode($r["roomusers"]) : "",
'profile' => (!empty($r["conf_profile"])) ? $r["conf_profile"] : "",
'desc' => (!empty($r["desc"])) ? $r["desc"] : "",
'pin' => (!empty($r["pin"])) ? $r["pin"] : "",
'layout' => (!empty($r["layout"])) ? $r["layout"] : "",
];
$rid = DB::table('rooms')->where('number', $r['number'])->value('id');
if( !empty($rid) ){
DB::table('rooms')->where('id', $rid)->update($roomData);
$retAns = $rid."_Upd";
} else {
$rid = DB::table('rooms')->insertGetId($roomData);
$retAns = $rid."_Ins";
}
}
return "ok";
} else {
return "File not saved";
}
}
public function generateRandomString($length = 10) {
$characters = '_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[rand(0, $charactersLength - 1)];
}
return $randomString;
}
private static function createRoomXml( $r ){
/*
//profile | cdquality_stereo_conferences
number | 7777
name | vMajlis
member_flags | join-vid-floor
*/
if( empty($r["number"]) || empty($r["name"]) ) { return false; }
if( !empty($r["member_flags"])) { $member_flags = "\t\t\t".'<action application="set" data="conference_member_flags='.$r["member_flags"].'"/>'."\n"; } else { $member_flags = ''; }
if( !empty($r["conf_profile"])) { $conf_profile = $r["conf_profile"]; } else { $conf_profile = 'vmj_default_profile'; } //video-mcu-stereo
if( !empty($r["conference_controls"])) { $conference_controls = "\t\t\t".$r["conference_controls"]."\n"; } else { $conference_controls = ''; }
return '<include>'."\n".
"\t".'<extension name="'.$r["name"].'">'."\n".
"\t\t".'<condition field="destination_number" expression="^('.$r["number"].')(\d)$">'."\n".
"\t\t\t".'<action application="jitterbuffer" data="50"/>'."\n".
"\t\t\t".'<action application="export" data="nolocal:jitterbuffer_msec=50"/>'."\n".
"\t\t\t".'<action application="set" data="rtp_jitter_buffer_plc=true"/>'."\n".
"\t\t\t".'<action application="answer"/>'."\n".
"\t\t\t".'<action application="send_display" data="'.$r["name"].'|$1"/>'."\n".
"\t\t\t".'<action application="set" data="video_mute_png=/usr/local/freeswitch/vmajlis_images/video-mute.png"/>'."\n".
"\t\t\t".'<action application="system" data="php /usr/local/freeswitch/conf/scripts/make_png_text.php \'${caller_id_name}\' \'/tmp/${caller_id_name}.png\' \'1920\' \'1080\'"/>'."\n".
"\t\t\t".'<action application="set" data="video_logo_path={position=center-bot}/tmp/${caller_id_name}.png"/>'."\n".
$member_flags.
$conference_controls.
"\t\t\t".'<action application="conference" data="$1@'.$conf_profile.'+flags{moderator}"/>'."\n".
"\t\t".'</condition>'."\n".
"\t".'</extension>'."\n".
'</include>';
/*
<condition field="destination_number" expression="^(7777)(\d)?$">
<action application="log" data="$1-$2"/>
<action application="jitterbuffer" data="50"/>
<action application="export" data="nolocal:jitterbuffer_msec=50"/>
<action application="set" data="rtp_jitter_buffer_plc=true"/>
<action application="answer"/>
<action application="send_display" data="Technounit-GROUP|$1"/>
<!--action application="set" data="rtp_video_max_bandwidth_in=512kb"/-->
<!--action application="set" data="rtp_video_max_bandwidth_out=512kb"/-->
<action application="set" data="video_mute_png=/usr/local/freeswitch/vmajlis_images/video-mute.png"/>
<action application="system" data="php /usr/local/freeswitch/conf/scripts/make_png_text.php '${caller_id_name}' '/tmp/${caller_id_name}.png' '1920' '1080'"/>
<action application="set" data="video_logo_path={position=center-bot}/tmp/${caller_id_name}.png"/>
<action application="conference" data="$1@vmj_default_profile+flags{moderator}"/>
</condition>
*/
}
/*
Metod: Save or create PROFILE
Usage: saveUser([num,password,name,<room>])
*/
public function saveLayout($arLayout){
if( (empty($arLayout["name"])) || (empty($arLayout["blocks"])) ){ return false; }
if( !is_array($arLayout["blocks"]) ) { return false; }
$lName = preg_replace('/[^a-zA-Z0-9]/', '', $arLayout["name"]);
if( empty($lName) ) { return false; }
$auto_3d_position = ( !empty($arProf["auto-3d-position"]) ) ? $arProf["auto-3d-position"] : "false";
$layout_temp = '<layout name="$lName" auto-3d-position="'.$auto_3d_position.'">
<image x="0" y="0" scale="144" floor="true"/>
<image x="144" y="0" scale="144"/>
<image x="288" y="0" scale="72"/>
<image x="288" y="72" scale="72"/>
<image x="288" y="144" scale="72"/>
<image x="0" y="216" scale="72"/>
<image x="72" y="216" scale="72"/>
<image x="144" y="216" scale="72"/>
<image x="216" y="216" scale="72"/>
<image x="288" y="216" scale="72"/>
<image x="0" y="288" scale="72"/>
<image x="72" y="288" scale="72"/>
<image x="144" y="288" scale="72"/>
<image x="216" y="288" scale="72"/>
<image x="288" y="288" scale="72"/>
</layout>';
if( $this->save_layout_file($lName, $peer_temp) ){
$response = $this->eRequest( "api reloadxml" );
return "ok";
}
}
/*
Metod: Save or create PROFILE
Usage: saveUser([num,password,name,<room>])
*/
public function saveProfile($arProf){
/*
name
video-layout-name (2top+15)
video-canvas-size (1920x1080)
video-canvas-bgcolor (#333333)
video-layout-bgcolor (#000000)
video-codec-bandwidth (2mb)
video-fps (30)
<!-- <param name="tts-engine" value="flite"/> -->
<!-- <param name="tts-voice" value="kal16"/> -->
*/
if( empty($arProf["name"]) ){ return "Name is empty"; }
$pName = preg_replace('/[^a-zA-Z]/', '', $arProf["name"]);
if( empty($pName) ) { return "Name is empty"; }
$video_layout_name = ( !empty($arProf["video-layout-name"]) ) ? $arProf["video-layout-name"] : "2top+15";
$video_canvas_size = ( !empty($arProf["video-canvas-size"]) ) ? $arProf["video-canvas-size"] : "1280x720";
$video_canvas_bgcolor = ( !empty($arProf["video-canvas-bgcolor"]) ) ? $arProf["video-canvas-bgcolor"] : "#333333";
$video_layout_bgcolor = ( !empty($arProf["video-layout-bgcolor"]) ) ? $arProf["video-layout-bgcolor"] : "#000000";
$video_codec_bandwidth = ( !empty($arProf["video-codec-bandwidth"]) ) ? $arProf["video-codec-bandwidth"] : "2mb";
$video_fps = ( !empty($arProf["video-fps"]) ) ? $arProf["video-fps"] : "30";
$peer_temp = '<profile name="'.$pName.'">
<param name="domain" value="$${domain}"/>
<param name="rate" value="48000"/>
<param name="channels" value="2"/>
<param name="interval" value="20"/>
<param name="energy-level" value="200"/>
<param name="muted-sound" value="conference/conf-muted.wav"/>
<param name="unmuted-sound" value="conference/conf-unmuted.wav"/>
<param name="alone-sound" value="conference/conf-alone.wav"/>
<param name="moh-sound" value="$${hold_music}"/>
<param name="enter-sound" value="tone_stream://%(200,0,500,600,700)"/>
<param name="exit-sound" value="tone_stream://%(500,0,300,200,100,50,25)"/>
<param name="kicked-sound" value="conference/conf-kicked.wav"/>
<param name="locked-sound" value="conference/conf-locked.wav"/>
<param name="is-locked-sound" value="conference/conf-is-locked.wav"/>
<param name="is-unlocked-sound" value="conference/conf-is-unlocked.wav"/>
<param name="pin-sound" value="conference/conf-pin.wav"/>
<param name="bad-pin-sound" value="conference/conf-bad-pin.wav"/>
<param name="caller-id-name" value="$${outbound_caller_name}"/>
<param name="caller-id-number" value="$${outbound_caller_id}"/>
<param name="comfort-noise" value="false"/>
<param name="conference-flags" value="video-floor-only|rfc-4579|livearray-sync|minimize-video-encoding"/>
<param name="video-mode" value="mux"/>
<param name="video-layout-name" value="'.$video_layout_name.'"/>
<param name="video-canvas-size" value="'.$video_canvas_size.'"/>
<param name="video-canvas-bgcolor" value="'.$video_canvas_bgcolor.'"/>
<param name="video-layout-bgcolor" value="'.$video_layout_bgcolor.'"/>
<param name="video-codec-bandwidth" value="'.$video_codec_bandwidth.'"/>
<param name="video-fps" value="'.$video_fps.'"/>
</profile>';
if( $this->save_profile_file($pName, $peer_temp) ){
$response = $this->eRequest( "api reloadxml" );
return "ok";
}
}
private function normalizeSimpleXML($obj, &$result) {
$data = $obj;
if (is_object($data)) {
$data = get_object_vars($data);
}
if (is_array($data)) {
foreach ($data as $key => $value) {
$res = null;
$this->normalizeSimpleXML($value, $res);
if (($key == '@attributes') && ($key)) {
$result = $res;
} else {
$result[$key] = $res;
}
}
} else {
$result = $data;
}
}
public function XML2JSON($file) {
if (!file_exists($file)) {
return false;
}
$xml = file_get_contents($file);
$this->normalizeSimpleXML(simplexml_load_string($xml), $result);
$json_ret = json_encode($result);
return json_decode($json_ret,TRUE);
}
private function getJsonReponseClean( $response ){
$pattern = '/(.*){(.*)}(.*)/m';
$replacement = '{$2}';
$response = preg_replace($pattern, $replacement, $response );
try {
$response = json_decode($response, true ) ;
} catch (Exception $e) {
return false ;
}
if( is_array( $response ) ){
return $response ;
}
return false ;
}
public function is_number_isset($num){
$users_path = config('vms.users_path');
return file_exists($users_path."vmj_".$num.".xml");
}
public function checkWrtcMdpUidEnter($i){
if( (empty($i["uid"])) || (empty($i["mdp"])) ){
return false;
}
$user = DB::table('clients')->where('id', $i['uid'])->where('password', $i["mdp"])->get();
$u = $user[0];
$users_path = config('vms.users_path');
if( !file_exists( $users_path ."vmj_".$u->number.".xml") ){
return false;
}
\Session::forget('ulogin');
\Session::forget('uname');
\Session::forget('unumber');
\Session::forget('upass');
\Session::forget('utocall');
\Session::set('ulogin',$u->login);
\Session::set('uname',$u->name);
\Session::set('unumber',$u->number);
\Session::set('upass',$u->password);
\Session::set('utocall',$u->room);
return $u;
}
public function addLiveStreamWatcher($i){
return DB::table('streamviewers')->insertGetId(
[
'datetime' => date("d.m.Y H:i:s"),
'timestamp' => time(),
'name' => $i["name"],
'login' => $i["login"],
'ip' => $i["ip"],
'brw' => $i["brw"],
'desc' => $i["desc"]
]
);
}
public function checkWrtcPassAndEnter($i){
if( empty($i["uid"]) ){
return "No User ID";
}
if( (empty($i["password"])) && (empty($i["mdpassword"])) ){
return "No Password";
}
/*if( (empty($i["uid"])) || (empty($i["password"]) && empty($i["mdpassword"])) ){
return false;
}*/
$hPass = (!empty($i["mdpassword"])) ? $i["mdpassword"] : md5($i['password']);
$user = DB::table('clients')->where('id', $i['uid'])->where('password', $hPass)->get();
if( !empty($user[0]) ){
return $this->enterToSystemIfGoodLogin($user[0]);
} else {
return "Bad Password (".$hPass .")";
}
}
public function enterToSystemIfGoodLogin($u){
if( $u->typeuser == "live" ){
\Session::forget('ulogin');
\Session::forget('uname');
\Session::forget('unumber');
\Session::forget('upass');
\Session::forget('uroom');
\Session::forget('utype');
\Session::set('ulogin',$u->login);
\Session::set('uname',$u->name);
\Session::set('unumber',$u->number);
\Session::set('upass',$u->password);
\Session::set('uroom',$u->room);
\Session::set('utype',$u->typeuser);
return json_decode(json_encode($u),true);
}
$users_path = config('vms.users_path');
if( !file_exists( $users_path ."vmj_".$u->number.".xml") ){
return false;
}
if( !empty($u->sharenum) ){
$s_sh = DB::table('clients')->where('login', $u->sharenum)->get();
$s = $s_sh[0];
\Session::forget('sharename');
\Session::forget('sharenum');
\Session::forget('shareroom');
\Session::forget('sharepass');
\Session::set('sharename',$s->name);
\Session::set('sharenum',$s->number);
\Session::set('sharepass',$s->password);
\Session::set('shareroom',$s->room);
}
$arDbRooms = DB::table('rooms')->get();
$uRooms = [];
foreach($arDbRooms as $aRm ){
if( !empty($aRm->users) ){
$rUsrs = json_decode($aRm->users);
if(in_array($u->number,$rUsrs)){
$uRooms[] = $aRm->number;
}
}
}
\Session::forget('ulogin');
\Session::forget('uname');
\Session::forget('unumber');
\Session::forget('upass');
\Session::forget('utocall');
\Session::forget('utype');
\Session::set('ulogin',$u->login);
\Session::set('uname',$u->name);
\Session::set('unumber',$u->number);
\Session::set('upass',$u->password);
\Session::set('utocall',$u->room);
\Session::set('utype',$u->typeuser);
return json_decode(json_encode($u),true);
}
public function checkWrtcLogin($i){
if( (empty($i["login"])) && (empty($i["number"])) ){
return false;
}
$users_path = config('vms.users_path');
if (is_numeric( $i["login"] ) ){
$uid = DB::table('clients')->where('number', $i['number'])->where('typeuser', "webrtc")->value('id');
if( !file_exists( $users_path ."vmj_".$i['number'].".xml") ){
return false;
}
//$user = DB::select('select * from client where number = ?', [$input['number']]);
} else {
$uid = DB::table('clients')->where('login', $i['login'])->where('typeuser', "webrtc")->value('id');
//$user = DB::select('select * from client where login = ?', [$input['login']]);
}
if( empty($uid) ){
return false;
} else {
return $uid;
}
}
/*EMILIO CHECK LOGIN DURING REGISTER*/
public function checkLoginForRegister($i){
if( empty($i["login"]) ){
return false;
}
$uid = DB::table('clients')->where('login', $i['login'])->where('typeuser', "webinar")->value('id');
if( empty($uid) ){
return false;
} else {
return $uid;
}
}
public function checkWebinarPassAndEnter($i){
if( empty($i["uid"]) ){
return "Login пустой";
}
if ( empty($i["password"]) ){
return "Password пустой";
}
$user = DB::table('clients')->where('id', $i['uid'])->where('password', md5($i['password']))->get();
if ( empty($user) ){
return "Пользователь не найден!";
}
$u = $user[0];
//$arRooms = DB::table('webinars')->where('client', $i['uid'])->value("room");
/*
UPDATE scores
SET scores.name = p.name
FROM scores s
INNER JOIN people p
ON s.personId = p.id
*/
$updQuery = "UPDATE visits"
." INNER JOIN webinars ON visits.room = webinars.room"
." SET visits.active = 'N'"
." WHERE webinars.client = ".$i['uid']."";
$ansVsts = DB::update($updQuery);
//var_dump($ansVsts);
\Session::put('uid', $u->id);
\Session::put('typeuser', $u->typeuser);
\Session::put('name', $u->name);
\Session::put('number', $u->number);
\Session::put('password', $u->password);
\Session::put('avatar', $u->avatar);
return true;
}
public function checkLoginAndRegister($i){
if( empty($i["login"]) ){
return "Login пустой";
}
if ( empty($i["password"]) ){
return "Password пустой";
}
$uid = DB::table('clients')->where('login', $i['login'])->value('id');
if ( !empty($uid) ){
return "Логин занят";
}
$arfNums = $this->get_all_xml_users();
$arWebinarNums = array_slice($arfNums,4100,4999);
$maxNum = $this->array_key_last($arWebinarNums);
$spr_number = (empty($maxNum)) ? 4100 : $maxNum+1;
/*$data = array(
$spr_number,
$i["login"],
md5($i["password"]),
"Speaker_".$i["login"],
"webinar"
);*/
$wid = DB::table('clients')->insertGetId(
[
'number' => $spr_number,
'login' => $i["login"],
'password' => md5($i["password"]),
'name' => "Speaker_".$i["login"],
'typeuser' => "webinar"
]
);
// = DB::insert('insert into clients (`number`, `login`, `password`, `name`, `typeuser`) values (?, ?, ?, ?, ?)',$data)
if( $wid ){
\Session::put('uid', $wid);
\Session::put('usertype', "webinar");
\Session::put('name', "Speaker_".$i["login"]);
//\Auth::loginUsingId($wid, true);
return $wid;
} else {
return "Error while saving user...";
}
}
/*TODO END*/
public function array_key_last($array) {
if (!is_array($array) || empty($array)) {
return NULL;
}
return array_keys($array)[count($array)-1];
}
private function get_all_xml_users(){
$users_path = config('vms.users_path');
$files = array_diff(scandir($users_path), array('.', '..'));
if( empty($files) ) {return "";}
$elems = array();
foreach( $files as $xmlf ){
$arUser = $this->XML2JSON( $users_path.$xmlf );
if(empty($arUser)){ continue; }
$elR = self::getUserDataFromXML($arUser);
if( !empty($elR["number"]) ){
$elems[$elR["number"]] = $elR;
}
}
return $elems;
}
public function get_one_layout($name){
if( empty($name) ){ return "";}
$lyt_path = config('vms.layouts_path');
if( file_exists( $lyt_path ."vmj_".$name.".xml") ) {
return $this->XML2JSON( $lyt_path ."vmj_".$name.".xml" );
} else {
return $lyt_path ."vmj_".$name.".xml"; //false;
}
}
public function get_all_layouts(){
$lyt_path = config('vms.layouts_path');
$files = array_diff(scandir($lyt_path), array('.', '..'));
if( empty($files) ) {return "Not files found";}
$elems = array();
foreach( $files as $xmlf ){
//$arLayout = $this->XML2JSON( $lyt_path.$xmlf );
if(empty($xmlf)){ continue; }
//$elR = self::getUserDataFromXML($arUser);
//$elems[$elR["number"]] = $elR;
$elems[] = substr($xmlf,4,-4);
}
return $elems;
}
public function isset_layout($name){
$layout_path = config('vms.layouts_path');
return file_exists($layout_path."vmj_".$name.".xml");
}
private function save_layout_file($name, $data){
$layout_path = config('vms.layouts_path');
if( $myfile = fopen($layout_path."vmj_".$name.".xml", "w")) {
fwrite($myfile, $data);
fclose($myfile);
return true;
} else {
return false;
}
}
private static function save_profile_file($name, $data){
$prof_path = config('vms.profiles_path');
if( $myfile = fopen($prof_path."vmj_".$name.".xml", "w")) {
fwrite($myfile, $data);
fclose($myfile);
return true;
} else {
return false;
}
}
private static function save_user_file($name, $data){
$users_path = config('vms.users_path');
if( $myfile = fopen($users_path."vmj_".$name.".xml", "w")) {
fwrite($myfile, $data);
fclose($myfile);
return true;
} else {
return false;
}
}
public function conf_record_stop($i){
if( empty($i["room"]) ){ return "No room";}
if( empty($i["path"]) ){ return "No path";}
$rec_line = 'conference '.$i["room"].' recording stop '.$i["path"];
$response = $this->eRequest( "api ".$rec_line );
return "ok";
}
public function conf_record_start($i){
//conference 7777 recording start /recordings/777_19_nov_12_56_25.mp4
if( empty($i["room"]) ){ return "No room";}
$recs_path = $rPath = config('vms.records_path');
$rec_line = 'conference '.$i["room"].' recording start '.$recs_path.''.$i["room"].'_'.date("d").'_'.date("M").'_'.date("H").'_'.date("i").'_'.date("s").'.mp4';
$response = $this->eRequest( "api ".$rec_line );
return "ok";
}
public function remove_room_file($name){
$rooms_path = $rPath = config('vms.rooms_path');
if( file_exists($rooms_path."vmj_".$name.".xml") ){
unlink( $rooms_path."vmj_".$name.".xml" );
$response = $this->eRequest( "api reloadxml" );
return "ok";
}
return $name." - file is not found. (".$rooms_path."vmj_".$name.".xml)";
}
private function save_room_file($name, $data){
$rooms_path = $rPath = config('vms.rooms_path');
if( $myfile = fopen($rooms_path."vmj_".$name.".xml", "w")) {
fwrite($myfile, $data);
fclose($myfile);
return true;
} else {
return false;
}
}
//SYSTEM INFOS
private function shapeSpace_system_load($interval = 1) {
$coreCount = $this->shapeSpace_system_cores();
$rs = sys_getloadavg();
$interval = $interval >= 1 && 3 <= $interval ? $interval : 1;
$load = $rs[$interval];
return round(($load * 100) / $coreCount,2);
}
private function shapeSpace_system_cores() {
$cmd = "uname";
$OS = strtolower(trim(shell_exec($cmd)));
switch($OS) {
case('linux'):
$cmd = "cat /proc/cpuinfo | grep processor | wc -l";
break;
case('freebsd'):
$cmd = "sysctl -a | grep 'hw.ncpu' | cut -d ':' -f2";
break;
default:
unset($cmd);
}
if ($cmd != '') {
$cpuCoreNo = intval(trim(shell_exec($cmd)));
}
return empty($cpuCoreNo) ? 1 : $cpuCoreNo;
}
private function shapeSpace_server_memory_usage() {
$free = shell_exec('free');
$free = (string)trim($free);
$free_arr = explode("\n", $free);
$mem = explode(" ", $free_arr[1]);
$mem = array_filter($mem);
$mem = array_merge($mem);
$memory_usage = $mem[2] / $mem[1] * 100;
return $memory_usage;
}
function shapeSpace_disk_usage() {
$disktotal = disk_total_space ('/');
$diskfree = disk_free_space ('/');
$diskuse = round (100 - (($diskfree / $disktotal) * 100));
return $diskuse;
}
public function is_port_open($host, $port){
//$host = '193.33.186.70';
//$port = 80;
$waitTimeoutInSeconds = 1;
if ($fp = fsockopen($host,$port,$errCode,$errStr,$waitTimeoutInSeconds)) {
$ret = true;
} else {
$ret = false;
}
fclose($fp);
return $ret;
}
public function apiCommand($cmd){
$response = $this->eRequest( "api ".$cmd );
return $response;
}
public function allCalls(){
$response = $this->eRequest( "api show calls" );
if( empty($response)) { return 0;}
else {
$arR = explode("\n",$response);
$cls = array();
$ch = array();
$ch = array();
foreach ( $arR as $a ){
if( strlen($a) < 15 ){
continue;
}
$arLine = explode(",",$a);
if( $arLine[0] == "uuid" ){
foreach( $arLine as $ah ){
$ch[] = $ah;
}
} else {
$onCall = array();
foreach( $arLine as $ak=>$ah ){
if(!empty($ch[$ak])){
$onCall[$ch[$ak]] = $ah;
}
}
$cls[] = $onCall;
}
}
}
//var_dump($cls);
return count($cls);
}
public function sysFullInfo(){
$cpu_stat = $this->shapeSpace_system_load(1);
$memory_stat = $this->shapeSpace_server_memory_usage();
$disk_stat = intval($this->shapeSpace_disk_usage());
$all_calls = $this->allCalls(); //TODO: SOMEWHAT NOT WORKING...
return array(
"cpu"=>$cpu_stat,
"memory"=>$memory_stat,
"disk"=>$disk_stat,
"calls"=>$all_calls
);
}
/* WebINARS*/
/* webinars
поле Тип Комментарий
id int(30) Автоматическое приращение
client int(20)
title varchar(250)
desc text
room int(10) unsigned
params text
files text
created tinytext
begin tinytext
*/
//
public function exitFromWebinar($i){
\Session::forget('webinar');
return true;
}
public function enterToMyLastWebinar($i){
/*$uid = \Session::get('uid');
$arWbnrs = DB::table('webinars')->where('client', $uid)->get();
$arWbnr = json_decode(json_encode($arWbnrs[0]),true);
$arWbnr['params'] = json_decode($arWbnr['params'],true);
\Session::set('webinar',$arWbnr);
*/
return true;
}
/*public function uploadFiles($data){
$input = $_POST['files'];
echo (json_encode($input));
}*/
public function enterToWebinarById($i){
if( !empty($i["wid"]) ) {
$arWebinars = DB::table('webinars')->where('id', $i["wid"])->get();
/*$arWbnr = json_decode(json_encode($arWbnrs[0]),true);
$arWbnr['params'] = json_decode($arWbnr['params']);
\Session::set('webinar',$arWbnr);*/
$webinar = json_decode(json_encode($arWebinars[0]),true);
$webinar['params'] = json_decode($webinar['params'],true);
\Session::put('webinar',$webinar);
return true;
}
}
public function removeMyWebinar($i){
if( empty($i["wid"]) ){
return "No Webinar ID";
} else {
$wroom = DB::table('webinars')->where('id', $i["wid"])->value('room');
$remans = $this->remove_room_file($wroom);
if( $remans == "ok" ){
DB::table('webinars')->where('id',$i["wid"])->delete();
return 0;
}
}
}
public function addNewWebinar($i){
$uid = \Session::get('uid');
if ( (!empty($i["begin_date"])) || (!empty($i["begin_time"])) ) {
$d = explode("/",$i["begin_date"]);
$t = explode(":",$i["begin_time"]);
$bDateTime = mktime($d[0],$d[1],0, $d[0],$d[1],$d[2]) ;
} else {
$bDateTime = time();
}
//vmj_webinar_profile
$cNums = config('vms.webinar_numbers');
$newNum = $this->getNewRoomNumberByMinMax($cNums[0],$cNums[1]);
$spr_number = (empty($newNum)) ? $cNums[0] : $newNum;
$title = ( !empty($i["title"]) ) ? strip_tags($i["title"]) : "Вебинар_".date("YmdHis");
$desc = ( !empty($i["descrition"]) ) ? strip_tags($i["descrition"]) : "_";
$arParams = array(
"resolution"=>( !empty($i["resolution"]) ) ? $i["resolution"] : "1920x1080",
"files"=>true,
"chat"=>true
);
$wCreate = time();
$wLink = $this->generateRandomString();
$wid = DB::table('webinars')->insertGetId(
[
'client' => (int)$uid,
'title' => $title,
'desc' => $desc,
'room' => (int)$spr_number,
'params' => json_encode( $arParams ),
'created' => $wCreate,
'begin' => $bDateTime,
'link' => $wLink
]
);
if( is_numeric($wid) ){
$sret = $this->saveRoom( array(
"number"=> $spr_number,
"name" => "vMajlis_Webinar_".$wid,
// "member_flags" => '<action application="set" data="conference_member_flags=moderator"/>',
"conference_controls" => '<action application="set" data="conference_controls=moderator"/>',
"conf_profile" => 'vmj_webinar_profile'
)
);
if( $sret == "ok"){
return $wid;
}else {
DB::table('webinars')->where('id',$wid)->delete();
return 'Can`t create webinar room!';
}
} else {
return 'Can`t create webinar to Database';
}
}
public function editMyWebinar($i){
if( empty($i["wid"]) ){
return "No Webinar ID";
} else {
$jParams = DB::table('webinars')->where('id', $i["wid"])->value('params');
}
$arParams = json_decode($jParams);
$editData = array();
if ( (!empty($i["begin_date"])) || (!empty($i["begin_time"])) ) {
$d = explode("/",$i["begin_date"]);
$t = explode(":",$i["begin_time"]);
$editData['begin'] = mktime($d[0],$d[1],0, $d[0],$d[1],$d[2]) ;
}
if ( !empty($i["title"]) ) { $editData['title'] = strip_tags($i["title"]); }
if ( !empty($i["descrition"]) ) { $editData['descrition'] = strip_tags($i["descrition"]); }
if( !empty($i["resolution"]) ){ $arParams["resolution"] = $i["resolution"]; }
if( isset($i["files"]) ){ $arParams["files"] = $i["files"]; }
if( isset($i["chat"]) ){ $arParams["chat"] = $i["chat"]; }
$editData['params'] = json_encode( $arParams );
DB::table('webinars')->where('id', $i["wid"])->update($editData);
return $editData;
}
public function create_png_from_text($args){
$font = "/usr/local/freeswitch/fonts/montserrat/Montserrat-Italic.otf";
if( empty($args) ){ $args = "Default";}
if( !is_array($args) ){
$args = array( 'text' => $args );
}
$width = ( !empty($args["width"]) ) ? (int)$args["width"] : 1280; //640; //1920; //640;
$height = ( !empty($args["height"]) ) ? (int)$args["height"] : 720; //480; //1080; //480;
$text = $args["text"];
if( strlen($text) > 150 ){
$text = substr($text,0,150);
$text = $text."...";
}
$file = ( !empty($args["file"]) ) ? $args["file"] : false;
if( $width > 1000 ){
$fontsize = 20;
} else {
$fontsize = 16;
}
$imgTxtBlock = imagecreate($width, 50);
$imgTxtBack = imagecreate($width, 50);
$img = imagecreate($width, $height);
$bTxtBlocks = imagecolorallocate($imgTxtBlock, 0, 0, 0);
imagecolorallocate($imgTxtBack, 255, 255, 255); //255, 255, 255
$black = imagecolorallocate($img, 0,0,0); //3, 169, 244
imagecolortransparent($img, $black);
//imagecolortransparent($imgTxtBlock, $bTxtBlocks);
$txtInTransparent = imagecolorallocate($imgTxtBlock, 255, 255, 255);
//$txtInTransparent = imagecolorallocate($img, 255, 255, 255);
$image_width = imagesx($img);
$image_height = imagesy($img);
$text_box = imagettfbbox($fontsize, 0, $font, $text);
$text_width = $text_box[0] - $text_box[2];
$text_height = $text_box[1] - $text_box[7];
$x = 30; //$image_width - ($text_width / 2);
$y = $image_height - ($text_height + 65);
imagettftext($imgTxtBlock, $fontsize, 0, 20, 30, $txtInTransparent, $font, $text);
imagecopymerge( $imgTxtBack, $imgTxtBlock, 0, 0, 0, 0, $image_width, 40, 60);
imagecopymerge( $img, $imgTxtBack, 0, $y, 0, 0, $image_width, 40, 100);
//imagettftext($img, $fontsize, 0, $x, $y, $txtInTransparent, $font, $text);
//imagettftext($img, $fontsize, 0, $x, $y, $txtInTransparent, $font, $text.'-['.$image_height.']-['.$text_height.']-['.$y.']' ); //For tests
if( !empty($file) ){
imagepng($img, $file);
imagedestroy($img);
imagedestroy($imgTxtBlock);
imagedestroy($imgTxtBack);
return "ok";
} else {
header('Content-Type: image/png');
imagepng($img);
imagedestroy($img);
imagedestroy($imgTxtBlock);
imagedestroy($imgTxtBack);
}
}
//getUserOS getUserIP getUserBrowser
public static function getUserIP(){
if (!empty($_SERVER['HTTP_X_FORWARD_FOR'])) {
return $_SERVER['HTTP_X_FORWARD_FOR'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['X-Real-IP'])) {
return $_SERVER['X-Real-IP'];
} elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
} elseif(!empty($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR'];
}
}
public static function getUserOS() {
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$os_platform = "Unknown OS Platform";
$os_array = array(
'/windows nt 10/i' => 'Windows 10',
'/windows nt 6.3/i' => 'Windows 8.1',
'/windows nt 6.2/i' => 'Windows 8',
'/windows nt 6.1/i' => 'Windows 7',
'/windows nt 6.0/i' => 'Windows Vista',
'/windows nt 5.2/i' => 'Windows Server 2003/XP x64',
'/windows nt 5.1/i' => 'Windows XP',
'/windows xp/i' => 'Windows XP',
'/windows nt 5.0/i' => 'Windows 2000',
'/windows me/i' => 'Windows ME',
'/win98/i' => 'Windows 98',
'/win95/i' => 'Windows 95',
'/win16/i' => 'Windows 3.11',
'/macintosh|mac os x/i' => 'Mac OS X',
'/mac_powerpc/i' => 'Mac OS 9',
'/linux/i' => 'Linux',
'/ubuntu/i' => 'Ubuntu',
'/iphone/i' => 'iPhone',
'/ipod/i' => 'iPod',
'/ipad/i' => 'iPad',
'/android/i' => 'Android',
'/blackberry/i' => 'BlackBerry',
'/webos/i' => 'Mobile'
);
foreach ($os_array as $regex => $value)
if (preg_match($regex, $user_agent))
$os_platform = $value;
return $os_platform;
}
public static function getUserBrowser() {
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$browser = "Unknown Browser";
$browser_array = array(
'/msie/i' => 'Internet Explorer',
'/firefox/i' => 'Firefox',
'/safari/i' => 'Safari',
'/chrome/i' => 'Chrome',
'/edge/i' => 'Edge',
'/opera/i' => 'Opera',
'/netscape/i' => 'Netscape',
'/maxthon/i' => 'Maxthon',
'/konqueror/i' => 'Konqueror',
'/mobile/i' => 'Mobile Browser'
);
foreach ($browser_array as $regex => $value)
if (preg_match($regex, $user_agent))
$browser = $value;
return $browser;
}
public function create_png_from_text_ORIG($args){
$font = "/usr/local/freeswitch/fonts/montserrat/Montserrat-Italic.otf";
if( empty($args) ){ $args = "Default";}
if( !is_array($args) ){
$args = array( 'text' => $args );
}
$width = ( !empty($args["width"]) ) ? (int)$args["width"] : 1280; //640; //1920; //640;
$height = ( !empty($args["height"]) ) ? (int)$args["height"] : 720; //480; //1080; //480;
$text = $args["text"];
if( strlen($text) > 150 ){
$text = substr($text,0,150);
$text = $text."...";
}
$file = ( !empty($args["file"]) ) ? $args["file"] : false;
if( $width > 1000 ){
$fontsize = 20;
} else {
$fontsize = 16;
}
$img = imagecreate($width, $height);
$black = imagecolorallocate($img, 0, 0, 0);
imagecolortransparent($img, $black);
$txtInTransparent = imagecolorallocate($img, 255, 255, 255);
$image_width = imagesx($img);
$image_height = imagesy($img);
$text_box = imagettfbbox($fontsize, 0, $font, $text);
$text_width = $text_box[0] - $text_box[2];
$text_height = $text_box[1] - $text_box[7];
$x = 30; //$image_width - ($text_width / 2);
$y = $image_height - ($text_height + 40);
imagettftext($img, $fontsize, 0, $x, $y, $txtInTransparent, $font, $text);
//imagettftext($img, $fontsize, 0, $x, $y, $txtInTransparent, $font, $text.'-['.$image_height.']-['.$text_height.']-['.$y.']' ); //For tests
if( !empty($file) ){
imagepng($img, $file);
imagedestroy($img);
return "ok";
} else {
header('Content-Type: image/png');
imagepng($img);
imagedestroy($img);
}
}
}
\ No newline at end of file
<?php
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/
return $app;
<?php
define('LARAVEL_START', microtime(true));
/*
|--------------------------------------------------------------------------
| Register The Composer Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/
require __DIR__.'/../vendor/autoload.php';
/*
|--------------------------------------------------------------------------
| Include The Compiled Class File
|--------------------------------------------------------------------------
|
| To dramatically increase your application's performance, you may use a
| compiled class file which contains all of the classes commonly used
| by a request. The Artisan "optimize" is used to create this file.
|
*/
$compiledPath = __DIR__.'/cache/compiled.php';
if (file_exists($compiledPath)) {
require $compiledPath;
}
<?php
return [
/*
|--------------------------------------------------------------------------
| Application Debug Mode
|--------------------------------------------------------------------------
|
| When your application is in debug mode, detailed error messages with
| stack traces will be shown on every error that occurs within your
| application. If disabled, a simple generic error page is shown.
|
*/
'debug' => env('APP_DEBUG', false),
/*
|--------------------------------------------------------------------------
| Application URL
|--------------------------------------------------------------------------
|
| This URL is used by the console to properly generate URLs when using
| the Artisan command line tool. You should set this to the root of
| your application so that it is used when running Artisan tasks.
|
*/
'url' => 'https://online.vmajlis.uz',
/*
|--------------------------------------------------------------------------
| Application Timezone
|--------------------------------------------------------------------------
|
| Here you may specify the default timezone for your application, which
| will be used by the PHP date and date-time functions. We have gone
| ahead and set this to a sensible default for you out of the box.
|
*/
'timezone' => 'Asia/Tashkent',
/*
|--------------------------------------------------------------------------
| Application Locale Configuration
|--------------------------------------------------------------------------
|
| The application locale determines the default locale that will be used
| by the translation service provider. You are free to set this value
| to any of the locales which will be supported by the application.
|
*/
'locale' => 'ru',
/*
|--------------------------------------------------------------------------
| Application Fallback Locale
|--------------------------------------------------------------------------
|
| The fallback locale determines the locale to use when the current one
| is not available. You may change the value to correspond to any of
| the language folders that are provided through your application.
|
*/
'fallback_locale' => 'en',
/*
|--------------------------------------------------------------------------
| Encryption Key
|--------------------------------------------------------------------------
|
| This key is used by the Illuminate encrypter service and should be set
| to a random, 32 character string, otherwise these encrypted strings
| will not be safe. Please do this before deploying an application!
|
*/
'key' => env('APP_KEY', 'irsnaKwaB1lE5Fp88oOD4L2BO9OkI02Q'),
'cipher' => 'AES-256-CBC',
/*
|--------------------------------------------------------------------------
| Logging Configuration
|--------------------------------------------------------------------------
|
| Here you may configure the log settings for your application. Out of
| the box, Laravel uses the Monolog PHP logging library. This gives
| you a variety of powerful log handlers / formatters to utilize.
|
| Available Settings: "single", "daily", "syslog", "errorlog"
|
*/
'log' => env('APP_LOG', 'daily'),
/*
|--------------------------------------------------------------------------
| Autoloaded Service Providers
|--------------------------------------------------------------------------
|
| The service providers listed here will be automatically loaded on the
| request to your application. Feel free to add your own services to
| this array to grant expanded functionality to your applications.
|
*/
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Foundation\Providers\ArtisanServiceProvider::class,
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
Illuminate\Routing\ControllerServiceProvider::class,
Illuminate\Cookie\CookieServiceProvider::class,
Illuminate\Database\DatabaseServiceProvider::class,
Illuminate\Encryption\EncryptionServiceProvider::class,
Illuminate\Filesystem\FilesystemServiceProvider::class,
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
Illuminate\Hashing\HashServiceProvider::class,
Illuminate\Mail\MailServiceProvider::class,
Illuminate\Pagination\PaginationServiceProvider::class,
Illuminate\Pipeline\PipelineServiceProvider::class,
Illuminate\Queue\QueueServiceProvider::class,
Illuminate\Redis\RedisServiceProvider::class,
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Illuminate\Session\SessionServiceProvider::class,
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
//App\Providers\TranslationServiceProvider::class
],
/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance.
|
*/
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
'Blade' => Illuminate\Support\Facades\Blade::class,
'Bus' => Illuminate\Support\Facades\Bus::class,
'Cache' => Illuminate\Support\Facades\Cache::class,
'Config' => Illuminate\Support\Facades\Config::class,
'Cookie' => Illuminate\Support\Facades\Cookie::class,
'Crypt' => Illuminate\Support\Facades\Crypt::class,
'DB' => Illuminate\Support\Facades\DB::class,
'Eloquent' => Illuminate\Database\Eloquent\Model::class,
'Event' => Illuminate\Support\Facades\Event::class,
'File' => Illuminate\Support\Facades\File::class,
'Gate' => Illuminate\Support\Facades\Gate::class,
'Hash' => Illuminate\Support\Facades\Hash::class,
'Input' => Illuminate\Support\Facades\Input::class,
'Lang' => Illuminate\Support\Facades\Lang::class,
'Log' => Illuminate\Support\Facades\Log::class,
'Mail' => Illuminate\Support\Facades\Mail::class,
'Password' => Illuminate\Support\Facades\Password::class,
'Queue' => Illuminate\Support\Facades\Queue::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
'Request' => Illuminate\Support\Facades\Request::class,
'Response' => Illuminate\Support\Facades\Response::class,
'Route' => Illuminate\Support\Facades\Route::class,
'Schema' => Illuminate\Support\Facades\Schema::class,
'Session' => Illuminate\Support\Facades\Session::class,
'Storage' => Illuminate\Support\Facades\Storage::class,
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class,
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Authentication Driver
|--------------------------------------------------------------------------
|
| This option controls the authentication driver that will be utilized.
| This driver manages the retrieval and authentication of the users
| attempting to get access to protected areas of your application.
|
| Supported: "database", "eloquent"
|
*/
'driver' => 'eloquent',
/*
|--------------------------------------------------------------------------
| Authentication Model
|--------------------------------------------------------------------------
|
| When using the "Eloquent" authentication driver, we need to know which
| Eloquent model should be used to retrieve your users. Of course, it
| is often just the "User" model but you may use whatever you like.
|
*/
'model' => App\User::class,
/*
|--------------------------------------------------------------------------
| Authentication Table
|--------------------------------------------------------------------------
|
| When using the "Database" authentication driver, we need to know which
| table should be used to retrieve your users. We have chosen a basic
| default value but you may easily change it to any table you like.
|
*/
'table' => 'users',
/*
|--------------------------------------------------------------------------
| Password Reset Settings
|--------------------------------------------------------------------------
|
| Here you may set the options for resetting passwords including the view
| that is your password reset e-mail. You can also set the name of the
| table that maintains all of the reset tokens for your application.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'password' => [
'login' => 'logins.password',
'table' => 'password_resets',
'expire' => 60,
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Broadcaster
|--------------------------------------------------------------------------
|
| This option controls the default broadcaster that will be used by the
| framework when an event needs to be broadcast. You may set this to
| any of the connections defined in the "connections" array below.
|
*/
'default' => env('BROADCAST_DRIVER', 'pusher'),
/*
|--------------------------------------------------------------------------
| Broadcast Connections
|--------------------------------------------------------------------------
|
| Here you may define all of the broadcast connections that will be used
| to broadcast events to other systems or over websockets. Samples of
| each available type of connection are provided inside this array.
|
*/
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_KEY'),
'secret' => env('PUSHER_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
//
],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
'log' => [
'driver' => 'log',
],
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Cache Store
|--------------------------------------------------------------------------
|
| This option controls the default cache connection that gets used while
| using this caching library. This connection is used when another is
| not explicitly specified when executing a given caching function.
|
*/
'default' => env('CACHE_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------
| Cache Stores
|--------------------------------------------------------------------------
|
| Here you may define all of the cache "stores" for your application as
| well as their drivers. You may even define multiple stores for the
| same cache driver to group types of items stored in your caches.
|
*/
'stores' => [
'apc' => [
'driver' => 'apc',
],
'array' => [
'driver' => 'array',
],
'database' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null,
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache'),
],
'memcached' => [
'driver' => 'memcached',
'servers' => [
[
'host' => '127.0.0.1', 'port' => 11211, 'weight' => 100,
],
],
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
],
],
/*
|--------------------------------------------------------------------------
| Cache Key Prefix
|--------------------------------------------------------------------------
|
| When utilizing a RAM based store such as APC or Memcached, there might
| be other applications utilizing the same cache. So, we'll specify a
| value to get prefixed to all our keys so we can avoid collisions.
|
*/
'prefix' => 'laravel',
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Additional Compiled Classes
|--------------------------------------------------------------------------
|
| Here you may specify additional classes to include in the compiled file
| generated by the `artisan optimize` command. These should be classes
| that are included on basically every request into the application.
|
*/
'files' => [
//
],
/*
|--------------------------------------------------------------------------
| Compiled File Providers
|--------------------------------------------------------------------------
|
| Here you may list service providers which define a "compiles" function
| that returns additional files that should be compiled, providing an
| easy way to get common files from any packages you are utilizing.
|
*/
'providers' => [
//
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| PDO Fetch Style
|--------------------------------------------------------------------------
|
| By default, database results will be returned as instances of the PHP
| stdClass object; however, you may desire to retrieve records in an
| array format for simplicity. Here you can tweak the fetch style.
|
*/
'fetch' => PDO::FETCH_CLASS,
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library.
|
*/
'default' => env('DB_CONNECTION', 'mysql'),
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple.
|
|
| All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development.
|
*/
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => database_path('database.sqlite'),
'prefix' => '',
],
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'vmj'),
'username' => env('DB_USERNAME', 'vmj'),
'password' => env('DB_PASSWORD', 'vmjp@ss'),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'schema' => 'public',
],
'sqlsrv' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run in the database.
|
*/
'migrations' => 'migrations',
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer set of commands than a typical key-value systems
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
'redis' => [
'cluster' => false,
'default' => [
'host' => env('REDIS_HOST', 'localhost'),
'password' => env('REDIS_PASSWORD', null),
'port' => env('REDIS_PORT', 6379),
'database' => 0,
],
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. A "local" driver, as well as a variety of cloud
| based drivers are available for your choosing. Just store away!
|
| Supported: "local", "ftp", "s3", "rackspace"
|
*/
'default' => 'local',
/*
|--------------------------------------------------------------------------
| Default Cloud Filesystem Disk
|--------------------------------------------------------------------------
|
| Many applications store files both locally and in the cloud. For this
| reason, you may specify a default "cloud" driver here. This driver
| will be bound as the Cloud disk implementation in the container.
|
*/
'cloud' => 's3',
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been setup for each driver as an example of the required options.
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'ftp' => [
'driver' => 'ftp',
'host' => 'ftp.example.com',
'username' => 'your-username',
'password' => 'your-password',
// Optional FTP Settings...
// 'port' => 21,
// 'root' => '',
// 'passive' => true,
// 'ssl' => true,
// 'timeout' => 30,
],
's3' => [
'driver' => 's3',
'key' => 'your-key',
'secret' => 'your-secret',
'region' => 'your-region',
'bucket' => 'your-bucket',
],
'rackspace' => [
'driver' => 'rackspace',
'username' => 'your-username',
'key' => 'your-key',
'container' => 'your-container',
'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/',
'region' => 'IAD',
'url_type' => 'publicURL',
],
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Mail Driver
|--------------------------------------------------------------------------
|
| Laravel supports both SMTP and PHP's "mail" function as drivers for the
| sending of e-mail. You may specify which one you're using throughout
| your application here. By default, Laravel is setup for SMTP mail.
|
| Supported: "smtp", "mail", "sendmail", "mailgun", "mandrill", "ses", "log"
|
*/
'driver' => env('MAIL_DRIVER', 'sendmail'),
/*
|--------------------------------------------------------------------------
| SMTP Host Address
|--------------------------------------------------------------------------
|
| Here you may provide the host address of the SMTP server used by your
| applications. A default option is provided that is compatible with
| the Mailgun mail service which will provide reliable deliveries.
|
*/
'host' => env('MAIL_HOST', 'smtp.yandex.ru'),
/*
|--------------------------------------------------------------------------
| SMTP Host Port
|--------------------------------------------------------------------------
|
| This is the SMTP port used by your application to deliver e-mails to
| users of the application. Like the host we have set this value to
| stay compatible with the Mailgun e-mail application by default.
|
*/
'port' => env('MAIL_PORT', 465),
/*
|--------------------------------------------------------------------------
| Global "From" Address
|--------------------------------------------------------------------------
|
| You may wish for all e-mails sent by your application to be sent from
| the same address. Here, you may specify a name and address that is
| used globally for all e-mails that are sent by your application.
|
*/
'from' => ['address' => "no-reply@vmajlis.uz", 'name' => "vMajlis webinars"],
/*
|--------------------------------------------------------------------------
| E-Mail Encryption Protocol
|--------------------------------------------------------------------------
|
| Here you may specify the encryption protocol that should be used when
| the application send e-mail messages. A sensible default using the
| transport layer security protocol should provide great security.
|
*/
'encryption' => env('MAIL_ENCRYPTION', 'tls'), //tls
/*
|--------------------------------------------------------------------------
| SMTP Server Username
|--------------------------------------------------------------------------
|
| If your SMTP server requires a username for authentication, you should
| set it here. This will get used to authenticate with your server on
| connection. You may also set the "password" value below this one.
|
*/
'username' => env('MAIL_USERNAME', "no-reply@vmajlis.uz"),
/*
|--------------------------------------------------------------------------
| SMTP Server Password
|--------------------------------------------------------------------------
|
| Here you may set the password required by your SMTP server to send out
| messages from your application. This will be given to the server on
| connection so that the application will be able to send messages.
|
*/
/*
MAIL_DRIVER=smtp
MAIL_HOST=smtp.yandex.ru
MAIL_PORT=465
MAIL_USERNAME=no-reply@vmajlis.uz
MAIL_PASSWORD=mteamgfhjkm
MAIL_ENCRYPTION=tls
*/
'password' => env('MAIL_PASSWORD', "mteamgfhjkm"),
/*
|--------------------------------------------------------------------------
| Sendmail System Path
|--------------------------------------------------------------------------
|
| When using the "sendmail" driver to send e-mails, we will need to know
| the path to where Sendmail lives on this server. A default path has
| been provided here, which will work well on most of your systems.
|
*/
'sendmail' => '/usr/sbin/sendmail -bs',
/*
|--------------------------------------------------------------------------
| Mail "Pretend"
|--------------------------------------------------------------------------
|
| When this option is enabled, e-mail will not actually be sent over the
| web and will instead be written to your application's logs files so
| you may inspect the message. This is great for local development.
|
*/
'pretend' => env('MAIL_PRETEND', false),
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Queue Driver
|--------------------------------------------------------------------------
|
| The Laravel queue API supports a variety of back-ends via an unified
| API, giving you convenient access to each back-end using the same
| syntax for each one. Here you may set the default queue driver.
|
| Supported: "null", "sync", "database", "beanstalkd",
| "sqs", "iron", "redis"
|
*/
'default' => env('QUEUE_DRIVER', 'sync'),
/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection information for each server that
| is used by your application. A default configuration has been added
| for each back-end shipped with Laravel. You are free to add more.
|
*/
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'expire' => 60,
],
'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => 'localhost',
'queue' => 'default',
'ttr' => 60,
],
'sqs' => [
'driver' => 'sqs',
'key' => 'your-public-key',
'secret' => 'your-secret-key',
'queue' => 'your-queue-url',
'region' => 'us-east-1',
],
'iron' => [
'driver' => 'iron',
'host' => 'mq-aws-us-east-1.iron.io',
'token' => 'your-token',
'project' => 'your-project-id',
'queue' => 'your-queue-name',
'encrypt' => true,
],
'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'expire' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
| can control which database and table are used to store the jobs that
| have failed. You may change them to any database / table you wish.
|
*/
'failed' => [
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, Mandrill, and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
'mandrill' => [
'secret' => env('MANDRILL_SECRET'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
];
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Session Driver
|--------------------------------------------------------------------------
|
| This option controls the default session "driver" that will be used on
| requests. By default, we will use the lightweight native driver but
| you may specify any of the other wonderful drivers provided here.
|
| Supported: "file", "cookie", "database", "apc",
| "memcached", "redis", "array"
|
*/
'driver' => env('SESSION_DRIVER', 'file'),
/*
|--------------------------------------------------------------------------
| Session Lifetime
|--------------------------------------------------------------------------
|
| Here you may specify the number of minutes that you wish the session
| to be allowed to remain idle before it expires. If you want them
| to immediately expire on the browser closing, set that option.
|
*/
'lifetime' => 1200,
'expire_on_close' => false,
/*
|--------------------------------------------------------------------------
| Session Encryption
|--------------------------------------------------------------------------
|
| This option allows you to easily specify that all of your session data
| should be encrypted before it is stored. All encryption will be run
| automatically by Laravel and you can use the Session like normal.
|
*/
'encrypt' => false,
/*
|--------------------------------------------------------------------------
| Session File Location
|--------------------------------------------------------------------------
|
| When using the native session driver, we need a location where session
| files may be stored. A default has been set for you but a different
| location may be specified. This is only needed for file sessions.
|
*/
'files' => storage_path('framework/sessions'),
/*
|--------------------------------------------------------------------------
| Session Database Connection
|--------------------------------------------------------------------------
|
| When using the "database" or "redis" session drivers, you may specify a
| connection that should be used to manage these sessions. This should
| correspond to a connection in your database configuration options.
|
*/
'connection' => null,
/*
|--------------------------------------------------------------------------
| Session Database Table
|--------------------------------------------------------------------------
|
| When using the "database" session driver, you may specify the table we
| should use to manage the sessions. Of course, a sensible default is
| provided for you; however, you are free to change this as needed.
|
*/
'table' => 'sessions',
/*
|--------------------------------------------------------------------------
| Session Sweeping Lottery
|--------------------------------------------------------------------------
|
| Some session drivers must manually sweep their storage location to get
| rid of old sessions from storage. Here are the chances that it will
| happen on a given request. By default, the odds are 2 out of 100.
|
*/
'lottery' => [2, 100],
/*
|--------------------------------------------------------------------------
| Session Cookie Name
|--------------------------------------------------------------------------
|
| Here you may change the name of the cookie used to identify a session
| instance by ID. The name specified here will get used every time a
| new session cookie is created by the framework for every driver.
|
*/
'cookie' => 'vmj_session',
/*
|--------------------------------------------------------------------------
| Session Cookie Path
|--------------------------------------------------------------------------
|
| The session cookie path determines the path for which the cookie will
| be regarded as available. Typically, this will be the root path of
| your application but you are free to change this when necessary.
|
*/
'path' => '/',
/*
|--------------------------------------------------------------------------
| Session Cookie Domain
|--------------------------------------------------------------------------
|
| Here you may change the domain of the cookie used to identify a session
| in your application. This will determine which domains the cookie is
| available to in your application. A sensible default has been set.
|
*/
'domain' => null,
/*
|--------------------------------------------------------------------------
| HTTPS Only Cookies
|--------------------------------------------------------------------------
|
| By setting this option to true, session cookies will only be sent back
| to the server if the browser has a HTTPS connection. This will keep
| the cookie from being sent to you if it can not be done securely.
|
*/
'secure' => false,
];
<?php
return [
/*
|--------------------------------------------------------------------------
| View Storage Paths
|--------------------------------------------------------------------------
|
| Most templating systems load templates from disk. Here you may specify
| an array of paths that should be checked for your views. Of course
| the usual Laravel view path has already been registered for you.
|
*/
'paths' => [
realpath(base_path('resources/views')),
],
/*
|--------------------------------------------------------------------------
| Compiled View Path
|--------------------------------------------------------------------------
|
| This option determines where all the compiled Blade templates will be
| stored for your application. Typically, this is within the storage
| directory. However, as usual, you are free to change this value.
|
*/
'compiled' => realpath(storage_path('framework/views')),
];
<?php
return [
"password" => "mteam",
"port" => "8021",
"host" => "127.0.0.1",
"rooms_path" => '/usr/local/freeswitch/conf/dialplan/vmajlis/',
"users_path" => '/usr/local/freeswitch/conf/directory/vmajlis/',
"profiles_path" => '/usr/local/freeswitch/conf/vmajlis_profiles/',
"layouts_path" => '/usr/local/freeswitch/conf/vmajlis_layouts/',
"videos_path" => dirname(__DIR__).'/videos/',
"records_path" => '/recordings/',
"webinar_client_numbers" => array(4100,4499),
"webinar_numbers" => array(8900,8999)
];
\ No newline at end of file
<?php
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| Here you may define all of your model factories. Model factories give
| you a convenient way to create models for testing and seeding your
| database. Just tell the factory how a default model should look.
|
*/
$factory->define(App\User::class, function (Faker\Generator $faker) {
return [
'name' => 'Tug', //$faker->name,
'login' => 'tug', //$faker->e164PhoneNumber,
'phone' => '+998912345678', //$faker->e164PhoneNumber,
'password' => Hash::make('mteam'), //bcrypt('mteam'),
'remember_token' => 'mteam', //str_random(10),
];
});
$factory->define(App\Room::class, function () {
return [
'name' => 'Xona1',
'pin' => '7777', //str_random(4),
'layout' => '2x2',
];
});
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('login')->unique();
$table->string('phone');
//$table->string('email')->unique();
$table->string('password', 60);
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePasswordResetsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('password_resets', function (Blueprint $table) {
//$table->string('email')->index();
$table->bigIncrements('id')->index();
$table->string('phone');
$table->string('token');
$table->timestamp('created_at');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('password_resets');
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateRoomsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('rooms', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('pin');
$table->string('layout');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('rooms');
}
}
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateSessionsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->unique();
$table->integer('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('sessions');
}
}
<?php
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
//Model::unguard();
// $this->call(UserTableSeeder::class);
//Model::reguard();
factory(App\User::class, 1)->create();
factory(App\Room::class, 1)->create();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment